本节我们主要学习怎么定义方法、怎么声明接口,等。
方法
Go语言没有类,但是我们可以在类型上定义方法。
方法有一个特殊的接受者参数的函数。
接受者出现在func
关键字和方法名之间的参数列表中。
比如说下面的例子,方法Abs
有一个类型为Vertex
的接受者。
|
|
方法及函数
方法仅仅是一个有接收者参数的函数。
可以把方法重写为一个函数,如下乳,Abs
可以被写为一个常规的方法
|
|
方法(续)
也可以为non-struct类型声明方法,
看下面的例子,数值类型MyFloat
有一个Abs
方法。
|
|
指针接收者
可以声明方法的接收者是指针。
看下面的例子,Scale
方法定义在*Vertex
之上。
这样可以修改接收者的值,如果不传指针,则是原始对象的一个拷贝。
|
|
指针和函数
也可以把方法重写成一个函数:
|
|
方法和间接指针
在之前的例子中,有一个指针参数的方法比如传入一个指针:
var v Vertex
ScaleFunc(v) // Compile error!
ScaleFunc(&v) // OK
而调用指针接收者的方法的时候,既不需要传入值也不需要传入指针:
var v Vertex
v.Scale(5) // OK
p := &v
p.Scale(10) // OK
对于语句v.Scale(5)
,会自动调用有指针接收者的方法。比如说,v.Scale(5)
会变为(&v).Scale(5)
,因为Scale
方法有一个指针接收者:
|
|
选择值接收者还是指针接收者
选择指针接收者有两个原因:
第一个原因是可以修改接收者指针的值。
第二个原因避免每次调用的时候复制值。
|
|
接口
接口类型是一组方法签名的集合。
接口类型的值可以存放实现这些方法的任何值。
|
|
接口的隐式实现
一个类型通过实现接口的方法来实现一个接口。不需要显示的声明,也没有”implements”关键字。
|
|
空接口
空接口没有指定任何方法:
interface{}
一个空接口可以存储任何类型的值。
空接口用来编写处理未知类型的值。比如说fmt.Print
处理许多interface{}
的参数:
|
|
类型断言
类型断言
t := i.(T)
上述语言断言接口值i
保存了具体的类型T
,并把具体T
的值分配给变量t
。
但是如果i
没有保存一个T
,上述的语句会出现错误。
为了测试
一个接口值是否保存了一个具体的类型,类型断言可以返回两个值:具体的类型值和断言是否成功。
t, ok := i.(T)
如果i
保存着T
,然后t
将会是具体的值,ok
将会是true。
反之,ok
将是false,t
将会是类型T
的零值。
|
|
类型switches
类型转换就像常规的转换语句一样,但是case是具体的类型而不是值。
switch v := i.(type) {
case T:
// here v has type T
case S:
// here v has type S
default:
// no match; here v has the same type as i
}
Stringers
最普通的接口之一是Stringer
type Stringer interface {
String() string
}
一个Stringer
是一个可以把它自己描述为一个字符串的类型。fmt
包寻找这个接口来打印值。
|
|
错误
Go程序使用error
值来表达错误状态。
error
类型是内建接口。
type error interface {
Error() string
}
函数经常返回一个error
值,调用程序通过调用error是否等于nil
来处理错误。
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
fmt.Println("Converted integer:", i)
一个nil的error
表示成功,一个non-nil的error
表示失败。
|
|