注意为什么建议用 *Vertec

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. type Abser interface {
  7. Abs() float64
  8. }
  9. func main() {
  10. var a Abser
  11. f := MyFloat(-3.1415926)
  12. v := Vertex{3, 4}
  13. // 直接把定义的接口赋给相应的变量就OK
  14. a = f
  15. fmt.Println(a.Abs())
  16. a = &v
  17. fmt.Println(a.Abs())
  18. fmt.Println(v)
  19. }
  20. type MyFloat float64
  21. func (f MyFloat) Abs() float64 {
  22. if f < 0 {
  23. return float64(-f)
  24. }
  25. return float64(f)
  26. }
  27. type Vertex struct {
  28. X, Y float64
  29. }
  30. //Abs 为啥接收者是Vertex还是*Vertex都不影响呢
  31. // 但是对于其是v自身是有影响的,如果是*Vertex这里的v值就改变了
  32. // 如果只是Vertex的话,这里的v值不变
  33. // 不过这两种只能选择一种
  34. func (v Vertex) Abs() float64 {
  35. v.X = v.X + 2
  36. v.Y = v.Y + 8
  37. return math.Sqrt(v.X*v.X + v.Y*v.Y)
  38. }

两种不同的接口赋值

  1. package main
  2. import "fmt"
  3. type Phone interface {
  4. call()
  5. }
  6. type Nokia struct{}
  7. type iPhone struct{}
  8. func (nokia Nokia) call() {
  9. fmt.Println("我是Nokia")
  10. }
  11. func (iphone iPhone) call() {
  12. fmt.Println("我是iPhone")
  13. }
  14. func main() {
  15. var phone Phone
  16. //这里用的是直接new
  17. phone = new(Nokia)
  18. phone.call()
  19. //这里用定义出一个变量,然后再把值赋给它的方式
  20. var iphone iPhone
  21. phone = iphone
  22. phone.call()
  23. }

类型里定义的变量接口方法里要用

  1. package main
  2. import "fmt"
  3. type I interface {
  4. M()
  5. }
  6. type T struct {
  7. S string
  8. }
  9. func (t T) M() {
  10. fmt.Println(t.S)
  11. }
  12. func main() {
  13. //实例化的时候就得赋值了
  14. var i I = T{"test"}
  15. i.M()
  16. }

接口值

即是 接口也是值,也可传递,其值为(value,type)
即使 接口值的value是nil,方法也会被nil接收者调用 即保存了nil具体值的接口自身并不是nil

var i I var t T i = t describle(i) //输出 (, main.T)

但是 nil 接口值既不保存具体值也不保存具体类型 ,调用方法会报错

  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. type I interface {
  7. M()
  8. }
  9. type T struct {
  10. S string
  11. }
  12. func (t *T) M() {
  13. fmt.Println(t.S)
  14. }
  15. type F float64
  16. func (f F) M() {
  17. fmt.Println(f)
  18. }
  19. func describle(i I) {
  20. fmt.Printf("(%v,%T)\n", i, i)
  21. }
  22. func main() {
  23. var i I
  24. //注意这里是怎么赋值的
  25. i = &T{"Hello"}
  26. describle(i) //(&{Hello},*main.T)
  27. i.M() //Hello
  28. i = F(math.Pi) //(3.141592653589793,main.F)
  29. describle(i) //3.141592653589793
  30. i.M()
  31. }

空接口

可以保存任意类型的值,因为任何类型都至少实现了零个方法
空接口常用来被处理未知类型的值,比如接收任意数量的参数

  1. package main
  2. import "fmt"
  3. func main() {
  4. //空接口
  5. var A interface{}
  6. describle(A) //<nil>,<nil>
  7. var a int
  8. describle(a) //0,int
  9. var s string
  10. describle(s) //,string
  11. }
  12. //注意这个参数声明
  13. func describle(i interface{}) {
  14. fmt.Printf("%v,%T\n", i, i)
  15. }

类型断言

用 t := i.(T)

该语句断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t
如果该 T 并不是i 的底层类型,那么将会产生一个panic

t, ok := i.(T)

同映射类似,如果是的返回OK,t是其底层值
如果不是,返回false ,t 的值是此处T 的零值

类型选择

switch结构来访问

  1. package main
  2. import "fmt"
  3. func doType(i interface{}) {
  4. switch t := i.(type) {
  5. case int:
  6. fmt.Printf("value is %v\n", t)
  7. case string:
  8. fmt.Printf("%q is %v bytes long\n", t, len(t))
  9. default:
  10. fmt.Printf("type is %T", t)
  11. }
  12. }
  13. func main() {
  14. doType(21)
  15. doType("hello")
  16. doType(true)
  17. }