• Go语言中接口interface(多接口,空接口,类别开关)的应用


    接口是一组方法签名的集合,然后我们可以定义一个结构体struct来实现该接口的所有方法,这样来看,接口就定义了对象的行为。
    对于接口大家都有着一定的了解,需要注意的就是实现接口,那就必须实现它里面的所有方法。

    我们定义一个形状Shape的接口,里面声明了周长与面积的两个方法,然后定义矩形Rectangle与圆形Circular的结构体类型,通过这个类型实现这些方法,由于方法都已在接口里面声明,所以矩形与圆形的类型也就实现了形状Shape接口。

    接口的实现

    1. package main
    2. import (
    3. "fmt"
    4. "math"
    5. )
    6. // 形状接口,声明周长与面积方法
    7. type Shape interface {
    8. Perimeter() float64
    9. Area() float64
    10. }
    11. // 矩形结构体:宽度与高度
    12. type Rectangle struct {
    13. Width float64
    14. Height float64
    15. }
    16. // 圆结构体:半径
    17. type Circular struct {
    18. Radius float64
    19. }
    20. // Rectangle实现周长的方法
    21. func (R Rectangle) Perimeter() float64 {
    22. return (R.Width + R.Height) * 2
    23. }
    24. // Rectangle实现面积的方法
    25. func (R Rectangle) Area() float64 {
    26. return R.Width * R.Height
    27. }
    28. // Circular实现周长的方法
    29. func (C Circular) Perimeter() float64 {
    30. return math.Pi * (C.Radius * 2)
    31. }
    32. // Circular实现面积的方法
    33. func (C Circular) Area() float64 {
    34. return math.Pi * (C.Radius * C.Radius)
    35. }
    36. func main() {
    37. var shape Shape = Rectangle{4.5, 5}
    38. fmt.Printf("%T,%#v,%#v\n", shape, shape.Perimeter(), shape.Area()) //main.Rectangle,19,22.5
    39. var shape2 Shape = Circular{6}
    40. fmt.Printf("%T,%.2f,%.2f", shape2, shape2.Perimeter(), shape2.Area())//main.Circular,37.70,113.10
    41. }

    从结果也看出这个类型是可以赋值给接口,赋值的类型不一样,其接口类型也跟着发生变化。就是说什么类型的赋值,接口就会成为这个具体的类型。

    参数是空接口

    空接口也就是说里面没有声明方法,啥都没有,我们来看下空接口作为方法参数的一个例子:

    1. package main
    2. import (
    3. "fmt"
    4. )
    5. type GetInfo string
    6. type Person struct {
    7. Name string
    8. Age int
    9. }
    10. // 空接口做参数
    11. func test(i interface{}) {
    12. fmt.Printf("%T,%#v\n", i, i)
    13. }
    14. func main() {
    15. getinfo := GetInfo("寅恪光潜")
    16. person := Person{"Tony", 18}
    17. test(getinfo) //main.GetInfo,"寅恪光潜"
    18. test(person) //main.Person,main.Person{Name:"Tony", Age:18}
    19. }

    我们可以看出test方法里面的参数是空接口,可以接收任意类型的参数,因为所有类型本已都实现了空接口。
    结果也正确显示了参数进来的类型与值,再次证明了上面接口的类型也是随着具体类型变化而变化的。

    多接口的实现

    想要实现多接口,其实跟实现一个接口类似,只不过多个接口里的方法都一一实现,既然方法都已实现,这样也就实现了多接口。
    我们定义两个形状接口,一个包含计算面积的方法,另一个包含计算体积的方法。然后我们分别将正方体类型赋值给这两个接口

    1. package main
    2. import "fmt"
    3. type Shape1 interface {
    4. Area() float64
    5. }
    6. type Shape2 interface {
    7. Volume() float64
    8. }
    9. // 正方体结构体:边长
    10. type Cube struct {
    11. Edge float64
    12. }
    13. // 面积
    14. func (C Cube) Area() float64 {
    15. return 6 * C.Edge * C.Edge
    16. }
    17. // 体积
    18. func (C Cube) Volume() float64 {
    19. return C.Edge * C.Edge * C.Edge
    20. }
    21. func main() {
    22. C := Cube{4}
    23. var S1 Shape1 = C
    24. var S2 Shape2 = C
    25. fmt.Printf("%#v\n", S1.Area()) //96
    26. fmt.Printf("%#v", S2.Volume()) //64
    27. }

    因为正方体Cube实现了面积与体积的方法,也就是这两个接口里的方法都实现了,所以就实现了两个接口。
    如果S1.Area() 换成 S1.Volume()会报错:

    Build Error: go build -o c:\Users\Tony\__debug_bin.exe -gcflags all=-N -l .
    # _/c_/Users/Tony
    .\test.go:30:25: S1.Volume undefined (type Shape1 has no field or method Volume) (exit status 2)

    因为这个S1接口里面是面积的方法,没有体积的方法,所以编译的时候就会报错。
    那既然是实现了多接口,那想要调用另外接口的方法,该如何处理呢?
    将用到类型的断言。类型断言的语法为:i.(Type)

    1. func main() {
    2. var S1 Shape1 = Cube{4}
    3. c := S1.(Cube)
    4. fmt.Println(c.Area()) //96
    5. fmt.Println(c.Volume()) //64
    6. }

    这样就可以分别去调用两个接口里面的方法了。
    当然了,这个类型是需要实现接口的,如果没有实现会报错,所以最好是有一种判断来处理。

    1. s1, ok := S1.(Cube)
    2. fmt.Println(s1, ok)//{4} true

    通过这个ok值来判断,为true就是实现了这个接口。

    1. type Tony interface {
    2.     Sing() string
    3. }
    4. s2, ok2 := S1.(Tony)
    5. fmt.Println(s2, ok2)// false

    由于Cube没有实现Sing方法,也就是没有实现Tony接口,所以第二个返回值就是false

    类型开关

    通过上面的学习,我们又回到上面的空接口的示例,针对输入的类型分别做判断:

    代码如下:

    1. package main
    2. import (
    3. "fmt"
    4. "strings"
    5. )
    6. type Person struct {
    7. Name string
    8. Age int
    9. }
    10. // 空接口参数
    11. func test(i interface{}) {
    12. switch i.(type) {
    13. case string:
    14. fmt.Printf("%#v\n", strings.ToUpper(i.(string)))
    15. case int:
    16. fmt.Printf("%#v\n", i)
    17. default:
    18. fmt.Printf("%T,%v", i, i)
    19. }
    20. }
    21. func main() {
    22. person := Person{"Tony", 18}
    23. test("hello")
    24. test(110)
    25. test(person)
    26. }
    27. /*
    28. "HELLO"
    29. 110
    30. main.Person,{Tony 18}
    31. */
  • 相关阅读:
    .sql数据库导入错误:/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */
    python之股票财务分析
    vivado跑完发邮件
    @RequestMapping 注解使用技巧
    富士康曲线救国,iPhone 15 Pro订单较上代有减少,iPhone 15增加
    全球最受欢迎的「数字游民」城市竟然是它?
    Spring——AOP
    MATLAB算法实战应用案例精讲-【图像处理】SLAM技术详解
    go的singleFlight学习
    推荐一个好用的微信、支付宝等Rust三方服务框架
  • 原文地址:https://blog.csdn.net/weixin_41896770/article/details/128201889