• Go奇技淫巧


    判断io读取是否结束,尽量用if n==0这种方式,因为可以判断很多种情况

    package main
    
    import (
        "fmt"
        "io"
        "net/http"
    )
    func handler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hello"))
        fmt.Println(r.Header)
    }
    
    func main() {
        resp, err := http.Get("http://www.baidu.com")
        if err != nil {
            return
        }
        buf := make([]byte, 4096)
        results := ""
        for {
            n, err := resp.Body.Read(buf)
            if n == 0 { //判断io读取是否结束,尽量用if n==0这种方式,因为可以判断很多种情况
                break
            }
            if err != nil && err != io.EOF {
                fmt.Println(err)
                break
            }
            results += string(buf[:n])
        }
        fmt.Println(results)
    }

    nil是有类型和值得,var *int = nil,它底层数据结构为(*int,data)

    接口为nil的充要条件为接口的运行时类型为nil,并且接口的运行时值为nil。这里将运行时的类型赋值为了File类型的指针

    var w io.Writer
    var f *os.File
    w = f
    fmt.Println(w == nil) //false
    这里为什么是false呢?原因是当File类型的指针赋值给Writer接口时,接口的类型被赋值为File类型的指针,而类型描述符被赋值为nil,而一个接口为nil的充要条件为接口的运行时类型为nil,并且接口的运行时值为nil。这里将运行时的类型赋值为了File类型的指针,因此是false。这显然不符合我们的预期,换种说法,这显然不是我们想要的结果,那我们如何进行更改呢?只需要将f的编译时类型改为io.Writer即可。因为两种类型是相同的,因此w = f进行赋值的时候,并不会改变运行时类型,又因为两个的值都是nil,所以运行时的值为nil,这样的话w == nil 就显然为true了

    当将空指针赋值给接口时,接口实例并不等于nil

    当把一个空指针对象赋值给一个interface后,再判断!= nil就不再成立了
    代码如下
    
    package main
    
    import "fmt"
    
    type Person interface {
        Name() string
    }
    
    type ChenQiongHe struct {
    }
    
    func (t *ChenQiongHe) Name() string {
        return "雪山飞猪"
    }
    
    func main() {
        var test *ChenQiongHe
        if test == nil {
            fmt.Println("test == nil")
        } else {
            fmt.Println("test != nil")
        }
        //将空指针赋值给接口
        var person Person = test
        if person == nil {
            fmt.Print("person == nil")
        } else {
            fmt.Print("person != nil")
        }
    }
    运行结果
    
    test == nil
    person != nil
    test本来是nil,赋值给person后居然不能再用nil判断了
    
    解决方法
    使用reflect包的IsNil判断,封装为一个能用方法
    
    func IsNil(i interface{}) bool {
        vi := reflect.ValueOf(i)
        if vi.Kind() == reflect.Ptr {
            return vi.IsNil()
        }
        return false
    }

    补充知识点:

    每当有一个进程启动时,系统会自动打开三个文件:标准输入,标准输出,标准错误--对应三个文件:stdin,stdout,stderr,当运行程序结束,系统自动关闭这三个文件

    结构体指针做函数返回值的时候

    不能返回局部变量的地址值。局部变量保存在栈帧上,函数调用结束后,栈帧释放,局部变量的地址,不再受系统保护,随时可能分配给其他程序局部变量的值可以返回

    内存对齐优化

    https://www.cnblogs.com/sunsky303/p/11315429.html

    结构体的地址等于首个元素的地址**

    package main
    
    import "fmt"
    
    type Person struct {
        name string
        sex  byte
        age  int
    }
    
    
    func main() {
        p := Person{"Jerry", '0', 26}
        fmt.Printf("%p
    ", &p)      //0xc000004460
        fmt.Printf("%p
    ", &p.name) //0xc000004460
    }
    
    用*加类型去调用结构体函数
    package main
    
    import (
       "fmt"
    )
    
    type N struct {
       int
    }
    
    func (n N) test() {
       fmt.Printf("%p
    %d
    ", &n, n)
    }
    
    func main() {
       var n N = N{2}
       fmt.Printf("%p
    %d
    ", &n, n)
       f1 := N.test
       f2 := (*N).test //可用*加类型去调用函数
       f1(n)
       f2(&n)
    }
    for;true;{} go里面的while true**
    var aa bool = true
        c := 0
        for ; aa; {
            fmt.Print(20)
            c++
            if c > 10 {
                aa = false
            }
    }
    两个函数相同类型相同的条件是拥有相同的形参列表和返回值列表(列表的次序,个数和类型都相同)行参名可以不同,以下两个函数类型是相同的
    func add(a,b int) int {
      return a+b
    }
    func sub(x int,y int) (c int){
      c = x-y;return c
    }

    可以通过type定义函数类型,函数类型变量可以作为函数的参数和返回值

    type Op func(int,int) int
    func add(a, b int) int {
      return a+b
    }
    func do (f Op, a, b int) int{
      return f(a, b)
    }
    
    func main(){
      a:=do(add, 1 ,2)
      fmt.print(a)
    }
    主动调用os.exit(1) defer将不会执行
    package main
    import "os"
    import "fmt"
    
    func main(){
      defer func(){
        fmt.Println("haha")
      }()
      os.Exit(1)
    }  //本函数不会打印haha

    defer一般放到错误语句检查之后,尽量不要放到循环语句中,相对于普通的函数调用,defer需要间接的数据结构的支持,相对于普通函数有一定的性能损耗





  • 相关阅读:
    java final修饰符
    java getClass()
    java color类简介
    JAVA本地方法详解,什么是JAVA本地方法?
    this 关键字
    main 静态方法 非静态方法
    Integer与int
    java创建一个对象时,内存中发生了什么
    java中静态变量在内存中的位置
    java使用new Date()和System.currentTimeMillis()获取当前时间戳
  • 原文地址:https://www.cnblogs.com/hualou/p/12069923.html
Copyright © 2020-2023  润新知