Type 关键字可以用来定义结构体:
type User struct {
Name string
age int
}
其实就是给原来的类型加一个别名,方便我们后面调用。
type str string
//在下面的代码中str就可以代替string使用了
var str1 str = "我是一个类型别名"
//这里不只是基础类型 结构体(复合类型)也可以使用别名
type (
I int
IA []int
U User
)
以上面的例子来说,后面的代码里 str 在很多场合都可以作为string关键字使用,但是它俩也有不一样的地方,这个我们后面会讲。
这里 我们定义一个 Speak 里面 包含一个方法call。
//这里 我们定义一个 Speak 里面 包含一个方法call
type Speak interface {
call() string
}
因为在Goland中,函数也是一种数据类型,具有相同参数和返回值的函数,我们认为它们的类型相同。(我们这里的相同指的是:个数、数据类型、顺序全部相同)。
其实,如果你把函数也当做一种类型来看的话,Type的这种使用方式跟我们说的第二种使用方式(类型别名)是一致的。
type handler func(string) int
接下来我们结合代码来看看它们的使用场景和要注意的点
首先我们定义一个函数,我们将它的参数指定为我们刚刚定义的handler 函数类型
func TestFunc(handler2 handler){
fmt.Println("这个函数的参数必须为函数类型 handler,并且接下里展示的是handler函数的执行结果")
//因为handler2 需要一个string 类型的参数我们这里给空串
handler2("")
}
当我们调用TestFunc的时候,我们需要一个handler类型的参数:
var handlerFunc handler = func(s string) int {
return 1
}
//这样执行时没问题的
TestFunc(handlerFunc)
既然上面说了,当函数的参数和返回值类型一致的时候,可以视为同一个类型,我们来看一个例子:
handlerFunc2 := func(s string) int {
return 2
}
TestFunc(handlerFunc2)
我们没有使用handler,直接定义了一个函数,可以看到在函数的参数和返回值一致的时候,同样可以作为TestFunc的参数。
注意:在绝大多数情况下,类型别名和源类型是等价的,但是也有例外的情况。比如我们在写方法的时候:
请看下面的例子:
func (h handler)call()string{
return "我是一个函数对象实现的接口"
}
func (s str)call()str{
return s
}
func (user User) call()str {
return ""
}
我们分别实现了三个方法,其实就是在别名str(对应string)、handler(对应 func(s string)int 函数类型、User(结构体 别名为U 上面有定义)。
handlerFunc.call()//这样是可以执行的
//但是 下面的写法确实不可以的
handlerFunc2.call()//编译器给出了一个错误"未解析的引用'call'"
//同理
var str1 str = "我是一个string的别名"
str1.call()//这样调用是没有问题的
var str2 string = "我是一个传统的字符串"
str2.call()//编译器报错了
user := User{}
user.call()//也没有问题
user1 := U{}
user1.call()//编译器报错
这个时候我们可以得出结论:在我们是有Type 定义类型别名(定义函数类型)的时候,他们所实现的方法是不互通的。