Skip to content

Instantly share code, notes, and snippets.

@chow1937
Created July 24, 2014 17:32
Show Gist options
  • Save chow1937/8a10726ccd3caf8a84cf to your computer and use it in GitHub Desktop.
Save chow1937/8a10726ccd3caf8a84cf to your computer and use it in GitHub Desktop.

TheWayToGo-day4

今天阅读的内容是第十一章和第十二章的前两个章节,其中,第十一章介绍的是 Go 语言的 interface 和 reflection。而 interface 是 Go 语言的一个非常重要的特性,通过 interface ,Go 语言可以实现多态,可以实现动态类型所谓的鸭子类型,所以多花了一些时间来理解这个概念。当然,看完也不能说是完全理解,还是需要通过项目实践。而 reflection 是通过 reflect 包实现的,实现了对类型的 reflection 可以为 Go 提供一些动态的特点。下面总结今天的要点。

### 第十一章:Interfaces and reflection

Go 语言不是一个传统的 OO 语言,它没有类,也没有继承,但是它通过一个非常灵活的概念,可以让使用者非常方便地实现 OO 的一些概念和层次,而又不需要处理传统 OO 语言那样复杂的东西。这个概念就是 interface,在我看来 interface 的概念很清楚。正如其本意所说明的,接口。一个实现了某个 interface 的方法的类型,就被认为可以用在使用这个 interface 的地方,比如接受这个 interface 作为参数的函数。通过 interface 还可以实现多态,下面是这章的要点:

1.首先是 interface 的定义形式:type name interface { Method1(param_list) return_type },一个 interface 可以有多个的 method,从这个形式看来,有点像是一组指定名名称的方法;

2.一个 interface 也可以被当做类型一样声明一个变量 var aI Namer

3.正如之前章节讲到的,一个 method 通常绑定了一个 receiver 也就是特定的类型,而一个 interface 值在内存中保存了该值指向的 receiver 和指向 method table 的指针;

4.如果一个类型定义了某个接口指定的 method ,则说这个类型实现了这个接口;

5.实现了某个接口的类型的变量可以赋给该接口的值变量;

6.一个类型不需要显式地声明实现某个接口;

7.一个实现了一个接口的类型也可以有其他的方法;

8.一个 interface 变量可以包含一个实现了这个 interface 的类型的实例变量的引用;

9.当两个不同的类型都实现了同一个接口的时候,我们可以把这两个类型的值都赋给这个接口的一个变量值,这样可以通过这个接口变量调用接口的方法,但是这两个类型的同名的方法却不是一样的表现,通过这个方式,可以见到我们实现了多态;

10.一个 interface 也可以包含其他的 interface ,这样可以组合不同的 interface 实现功能的组合;

11.interface 转换到类型的方式:v, ok = varI(T),其中 varI 一定是一个 interface 变量,如果类型 T 实现了这个接口,则返回 v 是 T 类型的变量,然后 ok 为 true;

12.检查一个类型是否实现了某个 interface:sv, ok = v.(InterfaceName),其中 v 为该类型的变量,返回该接口变量,包含一个指向该变量的引用;

13.如果一个类型想要实现某个接口,则必须要实现这个接口所定义的所有函数;

14.在调用实现了的 interface 方法的时候,指针方法可以由指针变量调用;

15.在调用实现了的 interface 方法的时候,值方法可以由值变量调用;

16.在调用实现了的 interface 方法的时候,值方法(指定义 receiver 为类型)的方法可以由指针变量调用,因为指针值可以先解引用;

17.在调用实现了的 interface 方法的时候,指针方法(指定义 *receiver 为类型)的方法不可以由值调用,因为存在一个 interface 变量中的值是没有地址的,只是一个拷贝;

18.如果一个 interface 什么方法都没有定义的时候,那么这个 interface 就称为空接口;

19.因为 empty interface 没有要求定义任何的方法,所以从另外一方面来说,任何的类型都实现了 empty interface;

20.定义一个空接口类型 type Any interface {}

21.根据上面提到的,任何类型的变量都可以赋给一个空接口的变量,所以根据这点我们可以将任何类型通过空接口结合起来;

22.空接口变量的 type assertion 得到的是该类型;

23.一个数据 slice 不能直接赋给一个接口 slice;

24.一个 interface 变量值可以赋给另外一个 interface 变量值,只要这个值的类型实现了这个 interface 指定的方法;

25.反射是编程中一种可以检查代码自身结构特别是类型的能力,反射可以用来实现在运行时调查值和类型;

26.可以通过 reflex.TypeOf() 函数取得一个变量的 reflex.Value 类型,然后通这个类型定义的 Kind Type``Float等方法获取该变量的特定的信息;

27.可以通过反射修改一个变量的值;

28.一个 struct 的 Value 对象有特别的方法,NumField 返回这个 struct 的 field 数量,Field(i)可以通过下标选取这个 struct 的指定偏移的 field;

29.甚至还可以通过 value.Method(0).Call(nil) 的方式调用一个 struct 定义的第一个方法;

30.实现了一个接口的类型的变量可以传给任何以该接口类型为参数的函数作为参数,通过这一点我们可以实现 Python 或者 Ruby 语言中所谓的鸭子类型;

31.虽然 Go 语言不支持函数重载,但是我们可以通过可变长度的参数和空接口来实现:args ...interface{} 这样一个参数,然后在不同类型实现的方法里面进行不同的处理;

第十二章: Reading and writing 1-2

这章目前只读到了前面的两个节,本章的内容主要是 Go 中的读取和写,这里的读取和写不单止是从文件,还可以是从 shell 中读取用户输入,也包括了各种 io 包的使用,下面先记录前两节的要点:

1.fmt.Scanln(format_str, &var1, &var2 ...) 可以从标准输入读取一行输入,也就是碰到换行符结束读取,内容根据 format_str 控制;

2.fmt.Sscan(str, format, &var1, &var2 ...) 可以从字符串读取指定的值,由 format 字符串控制;

3.bufio.NewReader(os.Stdin) 可以创建一个从标准输入读取数据的 reader;

4.一个 bufio.Reader 类型的变量可以用 ReadString('\n') 读取字符串,参数为分隔符,读到这个符号则结束读取;

5.当一个文件里面的内容每行用空格符分开一个个字段时,可以用 fmt.Fscanln(file, &v1, &v2 ...) 来读取,其中 file 为一个用 os.Open 函数打开的文件类型,而 v1 和 v2 将存储一行的第一个和第二个字段,之后的依次类推;

6.Go 中还可以先通过 os.Open 函数打开一个压缩文件,然后用相对应的压缩类型的包的 reader 来读取这个压缩文件,比如 gzip.NewReader 就创建了一个 gzip 类型压缩文件的 reader;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment