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值的定义,或者你认为另外一种类型是更有意义的)

版权声明本文仅代表作者观点,不代表本站立场。本文系作者授权发表,未经许可,不得转载。图文来源网络,侵权删!

搜索