go 基础
1、测试: go test -v xxx_test.go lib1.go lib2.go ..... (lib1.go lib2.go.... 是需要调用的文件,一般是测试的
2、基础数据的转换:
string -> int strconv.Atoi
string->int64 strconv.ParseInt(string,10,64)
int -> string strconv.Itoa
int64 ->string strconv.FormatInt(int64,10)
string -> float32/64 strconv.ParseFloat(s,32/64)
float ->string strconv.FormatFloat(float32/64,'E',-1,32/64)
3、bytes.Buffer
var b bytes.Buffer // 直接定义一个Buffer变量,不用初始化,可以直接使用
b := new(bytes.Buffer) //使用New返回Buffer变量
b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个Buffer
b := bytes.NewBufferString(s string) //从一个string变量,构造一个Buffer
往Buffer中写入数据
b.Write(d []byte) //将切片d写入Buffer尾部
b.WriteString(s string) //将字符串s写入Buffer尾部
b.WriteByte(c byte) //将字符c写入Buffer尾部
b.WriteRune(r rune) //将一个rune类型的数据放到缓冲器的尾部
从Buffer中读取数据到指定容器
c := make([]byte,8)
b.Read(c) //一次读取8个byte到c容器中,每次读取新的8个byte覆盖c中原来的内容
b.ReadByte() //读取第一个byte,b的第1个byte被拿掉,赋值给a => a, _ := b.ReadByte()
b.ReadRune() // 读取第一个rune,b的第1个rune被拿掉,赋值给r =>
r, _ := b.ReadRune()
b.ReadBytes(delimiter byte) // 需要一个 byte作为分隔符 ,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为byte类型的slice,返回后,缓冲器也会空掉一部分
b.ReadString(delimiter byte) // 需要一个 byte作为分隔符 ,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回, 作为字符串返回 ,返回后,缓冲器也会空掉一部分
4、fmt.print 系列
// Go 为常规 Go 值的格式化设计提供了多种打印方式。例 如,这里打印了 `point` 结构体的一个实例。
p := point{1, 2}
fmt.Printf("%v\n", p)
// 如果值是一个结构体,`%+v` 的格式化输出内容将包括结构体的字段名。
fmt.Printf("%+v\n", p)
// `%#v` 形式则输出这个值的 Go 语法表示。例如,值的运行源代码片段。
fmt.Printf("%#v\n", p)
// 需要打印值的类型,使用 `%T`。
fmt.Printf("%T\n", p)
// 格式化布尔值是简单的。
fmt.Printf("%t\n", true)
// 格式化整形数有多种方式,使用 `%d`进行标准的十进 制格式化。
fmt.Printf("%d\n", 123)
// 这个输出二进制表示形式。
fmt.Printf("%b\n", 14)
// 这个输出给定整数的对应字符。
fmt.Printf("%c\n", 33)
// `%x` 提供十六进制编码。
fmt.Printf("%x\n", 456)
// 对于浮点型同样有很多的格式化选项。使用 `%f` 进 行最基本的十进制格式化。
fmt.Printf("%f\n", 78.9)
// `%e` 和 `%E` 将浮点型格式化为(稍微有一点不同的)科学技科学记数法表示形式。
fmt.Printf("%e\n", 123400000.0)
fmt.Printf("%E\n", 123400000.0)
// 使用 `%s` 进行基本的字符串输出。
fmt.Printf("%s\n", "\"string\"")
// 像 Go 源代码中那样带有双引号的输出,使用 `%q`。
fmt.Printf("%q\n", "\"string\"")
// 和上面的整形数一样,`%x` 输出使用 base-16 编码的字符串,每个字节使用 2 个字符表示。
fmt.Printf("%x\n", "hex this")
// 要输出一个指针的值,使用 `%p`。
fmt.Printf("%p\n", &p)
// 当输出数字的时候,你将经常想要控制输出结果的宽度和 精度,可以使用在 `%` 后面使用数字来控制输出宽度。
// 默认结果使用右对齐并且通过空格来填充空白部分。
fmt.Printf("|%6d|%6d|\n", 12, 345)
// 你也可以指定浮点型的输出宽度,同时也可以通过 宽度. 精度 的语法来指定输出的精度。
fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
// 要左对齐,使用 `-` 标志。
fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
// 你也许也想控制字符串输出时的宽度,特别是要确保他们在 类表格输出时的对齐。这是基本的右对齐宽度表示。
fmt.Printf("|%6s|%6s|\n", "foo", "b")
// 要左对齐,和数字一样,使用 `-` 标志。
fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
// 到目前为止,我们已经看过 `Printf`了,它通过 `os.Stdout` 输出格式化的字符串。`Sprintf` 则格式化并返回一个字
// 符串而不带任何输出。
s := fmt.Sprintf("a %s", "string")
fmt.Println(s)
// 你可以使用 `Fprintf` 来格式化并输出到 `io.Writers` 而不是 `os.Stdout`。
fmt.Fprintf(os.Stderr, "an %s\n", "error")
var buf = new(bytes.Buffer)
fmt.Fprintf(buf, "[Debug] at %s() [%s:%d]\n", function(pc), file, line)
fmt.Fprintf(buf, "\n[Variables]\n")
for i := 0; i < len(data); i += 2 {
var output = fomateinfo(len(data[i].(string))+3, data[i+1])
fmt.Fprintf(buf, "%s = %s", data[i], output)
}
return buf.String()
5、os.Stat 获取文件信息
stat 结构:
st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。
os.stat返回err==nil,说明存在;
os.IsNotExist(err)为true,说明不存在;否则不确定是否存在
6、正则生成
re, err := regexp.Compile(patten)
if err != nil {
return
}
7、 fmt.Println(filepath.Join("Geeks", "for", "Geeks"))
8、随机数:
1、如果不使用rand.Seed(seed int64),每次运行,得到的随机数会一样,程序不停止,一直获取的随机数是不一样的;
2、每次运行时rand.Seed(seed int64),seed的值要不一样,这样生成的随机数才会和上次运行时生成的随机数不一样;
3、rand.Intn(n int)得到的随机数int i,0 <= i < n。
rand.Seed(time.Now().UnixNano())
list := rand.Perm(length) 生成的全排列下表数组
9、sync.Once
sync.Onc 是在代码运行中需要的时候执行,且只执行一次
10、互斥锁(sync.Mutex)和 读写锁(sync.RWMutex)
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个 goroutine 可以访问到共享资源(同一个时刻只有一个线程能够拿到锁)
在读多写少的环境中,可以优先使用读写互斥锁(sync.RWMutex),它比互斥锁更加高效。sync 包中的 RWMutex 提供了读写互斥锁的封装
读写锁分为:读锁和写锁
如果设置了一个写锁,那么其它读的线程以及写的线程都拿不到锁,这个时候,与互斥锁的功能相同
如果设置了一个读锁,那么其它写的线程是拿不到锁的,但是其它读的线程是可以拿到锁
var ( count int //读写锁 countGuard sync.RWMutex ) func read(mapA map[string]string){ for { countGuard.RLock() //这里定义了一个读锁 var _ string = mapA["name"] count += 1 countGuard.RUnlock() } } func write(mapA map[string]string) { for { countGuard.Lock() //这里定义了一个写锁 mapA["name"] = "johny" count += 1 time.Sleep(time.Millisecond * 3) countGuard.Unlock() } }
11、bufio 包介绍
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。
bufio.Read(p []byte) 相当于读取大小len(p)的内容,思路如下:
当缓存区有内容的时,将缓存区内容全部填入p并清空缓存区
当缓存区没有内容的时候且len(p)>len(buf),即要读取的内容比缓存区还要大,直接去文件读取即可
当缓存区没有内容的时候且len(p)<len(buf),即要读取的内容比缓存区小,缓存区从文件读取内容充满缓存区,并将p填满(此时缓存区有剩余内容)
以后再次读取时缓存区有内容,将缓存区内容全部填入p并清空缓存区(此时和情况1一样)
bufio.Write(p []byte) 的思路如下
判断buf中可用容量是否可以放下 p
如果能放下,直接把p拼接到buf后面,即把内容放到缓冲区
如果缓冲区的可用容量不足以放下,且此时缓冲区是空的,直接把p写入文件即可
如果缓冲区的可用容量不足以放下,且此时缓冲区有内容,则用p把缓冲区填满,把缓冲区所有内容写入文件,并清空缓冲区
判断p的剩余内容大小能否放到缓冲区,如果能放下(此时和步骤1情况一样)则把内容放到缓冲区
如果p的剩余内容依旧大于缓冲区,(注意此时缓冲区是空的,情况和步骤2一样)则把p的剩余内容直接写入文件
案例: 文件复制
readAll版本:
func DownFile() { url :="http://wx.qlogo.cn/Vaz7vE1/64" resp ,err := http.Get(url) if err != nil { fmt.Fprint(os.Stderr ,"get url error" , err) } defer resp.Body.Close() data ,err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } _ =ioutil.WriteFile("/tmp/icon_wx.png", data, 0755) }
bufio版本:
func DownFile() { url :="http://wx.qlogo.cn/Vaz7vE1/64" resp ,err := http.Get(url) if err != nil { fmt.Fprint(os.Stderr ,"get url error" , err) } defer resp.Body.Close() out, err := os.Create("/tmp/icon_wx_2.png") wt :=bufio.NewWriter(out) defer out.Close() n, err :=io.Copy(wt, resp.Body) fmt.Println("write" , n) if err != nil { panic(err) } wt.Flush() }
12、http.MaxBytesReader重置连接
s := http.Server{
Addr: ":8080",
Handler: &maxBytesReader{h:mux, n:4096},
}
log.Fatal(s.ListenAndServe())
13、Accept-Encoding规则
HTTP Header中Accept-Encoding 是浏览器发给服务器,声明浏览器支持的编码类型的。
常见的有
Accept-Encoding: compress, gzip //支持compress 和gzip类型
Accept-Encoding: //默认是identity
Accept-Encoding: * //支持所有类型
Accept-Encoding: compress;q=0.5, gzip;q=1.0 //按顺序支持 gzip , compress
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 // 按顺序支持 gzip , identity
服务器返回的对应的类型编码header是 content-encoding
服务器处理accept-encoding的规则如下所示
1. 如果服务器可以返回定义在Accept-Encoding 中的任何一种Encoding类型, 那么处理成功(除非q的值等于0, 等于0代表不可接受)
2. * 代表任意一种Encoding类型 (除了在Accept-Encoding中显示定义的类型)
3.如果有多个Encoding同时匹配, 按照q值顺序排列
4. identity总是可被接受的encoding类型(除非显示的标记这个类型q=0) , 如果Accept-Encoding的值是空 那么只有identity是会被接受的类型
如果Accept-Encoding中的所有类型服务器都没发返回, 那么应该返回406错误给客户端
如果request中没有Accept-Encoding 那么服务器会假设所有的Encoding都是可以被接受的,
如果Accept-Encoding中有identity 那么应该优先返回identity (除非有q值的定义,或者你认为另外一种类型是更有意义的)
版权声明本文仅代表作者观点,不代表本站立场。本文系作者授权发表,未经许可,不得转载。图文来源网络,侵权删!