理解 Go 类型系统

type的分类

按结构:

  • 基础类型,pre-declarered types:boolean,numeric and string
  • 复合类型,composite types:array,struct,map,slice,channel,func,interface 等

按名称:

  • Named Types:用type关键字定义,以及基础类型
  • Unamed types:是一个 literal type,也就是没有名字,只有 type 本身,像这样 [6]int 没有名字

underlying type:每一个类型都有自己的 underlying type ,如果 T 是 pre-declared type 或者 type literal,它们对应的 underlying type 就是自身 T,否则 T 的 underlying type 是T 定义时引用的类型的 underlying type

Underlying type 相同的 type

如果两个 type 的 underlying type 相同,则它们可以有以下特性:

  • 如果两个 type 都是 named type ,彼此之间不能相互赋值
  • 如果两个 type 其中一个是 unnamed type,彼此之间可以相互赋值

如果为一个类型起了名字,说明你想要做区分,所以两个 named types 即使 underlying name 相同也是不能相互赋值的

Named type 和 Unamed type 不同

当 named types 被作为一个 function 的 receiver 时,它就拥有了自己的方法,unamed types 则不能,这是它们的重要区别,pre-declare types 不能拥有自己的方法。

type 的属性继承一:直接继承

Declared named type 不会从它的 underlying type 或 existing type 继承 method,但是会继承 field

例外:

  • 如果 existing type 是 interface,它的 method set 会被继承
  • 如果 existing type 是 composite type,method也会被继承(如下?)

type 的属性继承二:type embedding

如果一个 type T‘ 被嵌入另一个 type T 作为它的 filed,T’ 的所有 field 和 method 都可以在 T 中使用,这种方法称之为 type embedding

由于内部类型的提升,内部类型实现的接口会自动提升到外部类型。这意味着由于内部类型的
实现,外部类型也同样实现了这个接口。

如果外部类型实现了 notify 方法,内部类型的实现就不会被提升。不过内部类型的值一直存在,因此还可以
通过直接访问内部类型的值,来调用没有被提升的内部类型实现的方法。

(《goinaction》)

type 转换

Type 之间是可以相互转换的,但要遵循一定的转换规则,详细请看官方规范 https://golang.org/ref/spec#Conversions。

关于接口

Go的类型系统的核心概念:我们不是根据我们的类型可以容纳的数据来设计抽象,而是根据我们的类型可以执行的操作来设计抽象。

定义一个接口:任何有Speak() string方法类型都是动物(Animal)

type Animal interface {
    Speak() string
}

如dog结构类型:

type Dog struct {
}

func (d Dog) Speak() string {
    return "Woof!"
}

cat结构类型:

type Cat struct {
}

func (c Cat) Speak() string {
    return "Meow!"
}

方法调用

func main() {
    //创建一个Animal接口类型的切片并用满足该接口的结构类型进行初始化
    animals := []Animal{Dog{}, Cat{}}
    //遍历该切片
    for _, animal := range animals {
        调用该结构类型的方法
        fmt.Println(animal.Speak())
    }
}

所有类型都满足空接口。这意味着如果您编写一个将interface{}值作为参数的函数,则可以为该函数提供任何值

func DoSomething(v interface{}){
   // ...
}

将接受任何参数。

v不是任何类型v不属于任何类型v是interface{}类型

所有值在运行时都只有一种类型,v的静态类型是interface{}

回到最初的例子,animals切片内的每个元素都是Animal类型,但不同值具有不同的基础类型

[]string的值是不能作为参数传入需要[]interface{}类型的函数的,需要经过如下转换(并不常用)

names:= [] string {“stanley “,”david“,”oscar“}
vals:= make([] interface {},len(names))
for i,v:= range names {
    vals [i] = v

[How to use interfaces in Go](How to use interfaces in Go) 还没看完

Comments