@ -0,0 +1,60 @@ | |||
# 接口 | |||
接口类型是对其他类型行为的概括和抽象,通过使用接口我们可以写出更加灵活和通用的函数 | |||
这些函数不用绑定在一个特定的类型实现上 | |||
对于一个具体类型 无须声明他实现了哪些接口,只要提供接口所必需的方法即可 | |||
# 接口即约定 | |||
之前介绍的类型都是具体类型, 具体类型指定了他所含的数据的精确布局 | |||
还暴露了基于这个精确布局的内部操作,比如对于数值有算术造作 | |||
对于slice类型有索引append range等 | |||
具体类型还会通过其他方法来提供额外的能力 | |||
总之你知道了一个具体类型的数据 你就精确的知道了他是什么以及他能干什么 | |||
Go中还有另外一种类型称为接口类型, 他是一种抽象类型, 并没有暴露所含的数据的布局或者内部结构, 当然也没有那些数据的基本操作 | |||
他所提供仅仅是一些方法而已。如果你拿到一个接口类型的值 你无从知道他是什么 仅仅知道他能做什么或者更精确的讲仅仅是他提供哪些方法 | |||
# 接口类型 | |||
一个接口类型定义一套方法 | |||
如果一个具体类型要实现该接口 | |||
那么必须实现接口类型定义的所有方法 | |||
接口还可以通过组合得到新的接口 | |||
另外接口类型中方法的定义的顺序是无意义的,真正有意义的只有接口的方法集合 | |||
# 实现接口 | |||
如果一个类型实现了一个接口要求的所有方法, 那么这个类型实现了这个接口 | |||
通常所说的 具体类型是一个特定的接类型 这就代表这改具体类型实现了改接口 | |||
# 接口赋值规则 | |||
仅当一个表达式实现了一个接口时 这个表达式才可以赋值给该接口 | |||
# 空接口类型 interface{} | |||
可以把任何值赋给控接口类型 | |||
这样函数就能接受任意类型的参数了啦啦啦啦啦啦 | |||
当然我们创建一个执行布尔值 浮点数 字符串 map 指针或其他类型的interface{}接口 也无法直接使用其中的值 | |||
毕竟这个接口不包含任何方法 我们需要一个方法从空接口中还原出实际值 | |||
判断是否实现接口只需要毕竟具体类型和接口类型的方法 所以没必要在具体类型的定义中声明这种关系 | |||
# 接口值 | |||
从概念上讲 一个接口类型的值简称接口值 其实有两个部分 一个具体类型和该类型的一个值 二者称为接口的动态类型和动态值 | |||
接口的零值就是把它的动态类型和值都设置为nil 可以用 ==nil 或者 != nil来检测一个接口值是否为nil | |||
调用一个nil接口的任何方法都会导致崩溃 | |||
一般来讲 在编译时 无法知道接口值的动态类型是什么, 所以通过接口来做调用必然需要使用动态分发 | |||
编译器必须生成一段代码来从类型描述符拿到名为write的方法地址 在间接调用该方法地址 调用这接收就是接口值的动态值 | |||
一个接口值可以指向任意大的动态值 | |||
接口值是可以比较的 所以他可以作为map的key 也可以作为switch的语句操作数(仅仅能确认接口值包含动态值可以比较时 才能比较接口值 不然会崩溃) | |||
P158 | |||
@ -0,0 +1,8 @@ | |||
# 方法申明 | |||
方法的声明和普通哈数的什么类似, 只是在函数名字前面多了一个参数。 | |||
这个参数把这个方法绑定到这个参数对应的类型上 | |||
命名类型(Point)与指向它们的指针 是唯一可以出现在接收这声明处的类型 | |||
而且为防止混淆 不允许本身是指针的类型进行方法声明 | |||
type P *int | |||
func (p P) f() {/* ... */} //编译错误 非法的接受者类型 |
@ -0,0 +1,35 @@ | |||
package geometry | |||
import "math" | |||
type Point struct {X, Y float64} | |||
// 普通函数 | |||
func Distance(p, q Point) float64 { | |||
return math.Hypot(q.X-p.X, q.Y-p.Y) | |||
} | |||
// Point类型的方法 | |||
func (p Point) Distance(q Point) float64 { | |||
return math.Hypot(q.X-p.X, q.Y-p.Y) | |||
} | |||
type Path []Point | |||
func (path Path) Distance() float64 { | |||
sum := 0.0 | |||
for i := range path { | |||
if i > 0 { | |||
sum += path[i-1].Distance(path[i]) | |||
} | |||
} | |||
return sum | |||
} | |||
func (p *Point) ScaleBy(factor float64) { | |||
p.X *= factor | |||
p.Y *= factor | |||
} |
@ -0,0 +1,26 @@ | |||
package main | |||
import ( | |||
"fmt" | |||
"./geometry" | |||
) | |||
func main() { | |||
p := geometry.Point{1, 2} | |||
q := geometry.Point{4, 6} | |||
fmt.Println(geometry.Distance(p, q)) | |||
fmt.Println(p.Distance(q)) | |||
perim := geometry.Path{{1,1}, {5,1}, {5,4}, {1,1}} | |||
fmt.Println(perim.Distance()) | |||
pptr := &geometry.Point{7, 7} | |||
pptr.ScaleBy(2.0) | |||
fmt.Println(*pptr) | |||
(*pptr).ScaleBy(2.0) | |||
fmt.Println(*pptr) | |||
fmt.Println((*pptr).Distance(q)) | |||
p.ScaleBy(2.0) | |||
fmt.Println(p) | |||
} |
@ -0,0 +1,32 @@ | |||
package io | |||
type Reader interface { | |||
Read(p []byte) (n int, err error) | |||
} | |||
type Writer interface { | |||
Write(p []byte) (n int, err error) | |||
} | |||
type Closer interface { | |||
Close() error | |||
} | |||
type ReadWriter interface{ | |||
Reader | |||
Writer | |||
} | |||
type ReadWriteCloser interface { | |||
Reader | |||
Writer | |||
Closer | |||
} | |||
//还可以混合定义 | |||
type ReadWriteCloser2 interface { | |||
Reader | |||
Writer | |||
Close() error | |||
} | |||