Go语言实战 学习笔记

1.json 包的 NewDecoder 函数

    // 打开文件
    file, err := os.Open(dataFile)
    if err != nil {
        return nil, err
    }

    defer file.Close()

    // 将文件解码到一个切片里
    var feeds []*Feed
    err = json.NewDecoder(file).Decode(&feeds)

使用调用Open返回的文件句柄调用NewDocoder函数,并得到一个指向Decoder类型的值得指针。之后再调用这个指针的Decode方法,传入切片的地址。之后Decode方法会解码数据文件,并将解码后的值以Feed类型值的形式存入切片里。

 func (dec *Decoder) Decode(v interface{}) error        

Decode方法接受一个类型为interface{}的值作为参数。这个参数在Go语言里很特殊,一般会配合reflect包里提供的反射功能一起使用。  

 

2.接收者是值类型或者指针类型的区别

如果函数带有接收者,就意味声明了一个方法,这个方法会和指定的接收者的类型绑在一起,这就意味着可以使用接收者类型的值或者指向这个类型值的指针来调用该方法。无论我们是使用接收者类型的值来调用方法,还是使用接收者类型值的指针来调用这个方法,编译器都会正确地引用或者解引用对应的值:

// 方法声明为使用defaultMatcher类型的值作为接收者
func (m defaultMatcher) Search(feed *Feed, searchTerm string)

// 声明一个指向 defaultMatcher 类型值的指针
dm := new(defaultMatch)

// 编译器会解开 dm 指针的引用,使用对应的值调用方法
dm.Search(feed, "test")

// 方法声明为使用指向 defaultMatcher 类型值的指针作为接收者
func (m *defaultMatcher) Search(feed *Feed, searchTerm string)

// 声明一个 defaultMatcher 类型的值
var dm defaultMatch

// 编译器会自动生成指针引用 dm 值,使用指针调用方法
dm.Search(feed, "test")

因为大部分方法在被调用后都需要维护接收者的值得状态,所以一个最佳实践是将方法的接收者声明为指阵。对于空结构体来说,使用值作为接收者是因为创建一个结构体类型的值不需要分配内存。由于空结构体不需要维护状态,所以不需要指针形式的接收者。

与直接通过值或者指针调用方法不同,如果通过接口类型的值调用方法,规则有很大的不同,使用指针作为接收者声明的方法,只能在接口类型的值是一个指针的时候被调用。使用值作为接收者声明的方法,在接口类型的值为值或指针时,都可以被调用。

// 方法声明为使用指向 defaultMatcher 类型值的指针作为接收者
func (m *defaultMatcher) Search(feed *Feed, searchTerm string)

// 通过interface类型的值来调用方法
var dm defaultMatcher
var matcher Matcher = dm
matcher.Search(feed, "test")

> go build 
cannot use dm (type defaultMatcher) as type Matcher in assignment

// 方法声明为使用 defaultMatcher 类型的值作为接收者
func (m defaultMatcher) Search(feed *Feed, searchTerm string)

// 通过interface类型的值来调用方法
var dm defaultMatcher
var matcher Matcher = dm
matcher.Search(feed, "test")

> go build
Build Successful

 

3.引用类型

  Go语言里的引用类型有切片、映射、通道、接口和函数类型。当声明上述类型的变量时,创建的变量被称作为标头(header)值。从技术细节上说字符串也是一种引用类型。每个引用类型创建的标头值是包含一个指向底层数据结构的指针。每个引用类型还包含一组独特的字段,用于管理底层数据结构。因为标头值是为复制而设计的,所以永远不需要共享一个引用类型的值。标头值里包含一个指针,因此通过复制来传递一个引用类型的值的副本,本质上就是在共享底层数据结构。(解释go语言都是值传递

 

4.结构类型

  1. 原始类型,指的是内建基本类型,比如int,byte,string等。
  2. 非原始是指用户自定义类型,比如用户自定义的 struct。
  3. 因为内建类型本身大小很小,所以传值和传引用(应该是传指针)区别不大,而自定义的struct 往往可能会包含很多字段,在比较大的情况下,传(引用)指针会避免值拷贝,从而提高效率。
  4. 不要一味的进行传(引用)指针,还要考虑逃逸分析问题,过多的引用会加大gc负担。
  5. go中默认值传递,闭包中特殊处理,会引用可见域中的变量,而不是值传递。

  如果结构类型的本质是原始的,对这个类型的值做增加或删除的操作不应该更改值得本身;相反,如果结构类型的本质是非原始的,对这个类型的值做增加或删除的操作应该更改值得本身。  

  使用值接收者还是指针接收者,不应该由该方法是否修改了接收到的值来决定。这个决策应该基于该类型的本质。本质为原始类型时传递值,本质为非原始类型时传递引用(指针)。

 

posted @ 2020-09-08 17:18  顽强的allin  阅读(210)  评论(0编辑  收藏  举报