Go 学习笔记介绍 8 接口、类型断言、类型开关

介绍

这是来自 Funai Research Institute Digital 的 osw。我决定在工作中使用 Go 语言,所以我将从现在开始学习它。这是备忘录。如果您可以参考,我将不胜感激。

目标听众

  • 正在学习围棋的人
  • 那些已经学习过其他语言基本语法的人

学习环境

学习环境是这样的:下面这篇文章总结了这个环境的搭建备忘录。如果您有兴趣,请参考它。

  • Windows 11 家庭版 / 22H2
  • VSCode/1.72.2
  • go 版本 go1.19.2 windows/amd64
  • git 版本 2.38.0.windows.1

以前的学习

上次我们学习了方法。

界面

似乎 Java 和 C++ 准备作为抽象实现和实现多态性的一种手段。至于如何使用,定义一个只收集没有定义的函数声明的接口,在Java中称为抽象方法,在C++中称为纯虚函数,通过“实现”它来使用。

但是,我不太明白措辞,但显然,在 Go 中实现接口意味着将接口中声明的函数定义为方法,并通过将其与接收者链接来“实现”接口。似乎表达看起来图像如下。

  1. 定义接口
  2. 实现接口的功能
  3. 将接收器绑定到实现的函数并使其成为方法
  4. 附加到方法的接收器“实现”接口

    如果将语法用户类型绑定为接收者,则该用户类型将实现一个接口。 Java 中没有关键字“implements”。

    句法

    // ユーザ型の定義
    type ユーザ型名 型
    
    // インタフェース定義
    type インタフェース名 interface {
        メソッド名
    }
    
    // メソッドの実装
    func (レシーバ 型) メソッド名() {
            // 処理
    }
    

    示例代码

    package main
    
    import "fmt"
    
    // ユーザ型の定義
    type AmericanShorthair int
    type Munchkin          int
    
    // にゃーインタフェース定義
    type IMeow interface {
        Meow()
    }
    
    // アメショの実装
    // この時点でAmericanShorthair型はIMeowインタフェースを実装している
    func (cat AmericanShorthair) Meow() {
            fmt.Println("にゃー")
    }
    
    // マンチカンの実装
    // この時点でMunchkin型はIMeowインタフェースを実装している
    func (cat Munchkin) Meow() {
            fmt.Println("なおーん")
    }
    
    func main() {
            // インタフェース型変数にそれぞれ格納
            // 格納される要素それぞれの型はインタフェースを実装済みなので代入できる
            cats := []IMeow{
                    AmericanShorthair(0),
                    Munchkin(0),
            }
    
            for _, cat := range cats {
                    cat.Meow()
            }
    }
    

    执行结果

    にゃー
    なおーん
    

    空接口

    它是一种可以接收任何东西的类型。但是,界面似乎是相同的。接口类型变量不能分配给任何不实现接口的东西,所以似乎所有类型都实现了空接口,因为空接口可以接收任何东西。

    句法

    var v interface{}
    

    示例代码

    package main
    
    import "fmt"
    
    func main() {
            var v interface{}
    
            v = 1
            fmt.Println(v)
    
            v = "test"
            fmt.Println(v)
    
            v = [...]int{0, 1, 2, 3, 4}
            fmt.Println(v)
    
            v = []int{0, 1, 2, 3, 4}
            fmt.Println(v)
    
            v = map[int]string {
                    0: "abc",
                    1: "def",
            }
            fmt.Println(v)
    }
    

    执行结果

    1
    test
    [0 1 2 3 4]
    [0 1 2 3 4]
    map[0:abc 1:def]
    

    类型断言

    空接口可以接收任何值,但似乎不再看到原始类型信息,无法访问它拥有的字段和值。因此,有一种方法可以将接口类型中接收到的值强制转换为任何类型,并且似乎是一种类型断言。

    句法

    // 変換できればokにtrue、valueにその値が返る。できなければfalse, ゼロ値が返る
    value, ok := インタフェース型変数.(任意の型)
    

    示例代码

    package main
    
    import "fmt"
    
    type Person struct {
            Name string
            Age  int
    }
    
    func main() {
            var i interface{}
    
            /*
             * アクセスできないことの確認
             */
            fmt.Println("構造体で中身にアクセスできるか確認")
            i = Person{
                    "tanaka",
                    99,
            }
            fmt.Println(i)
            // fmt.Println(i.Name) i.Name undefined (type interface{} has no field or method Name)
            // fmt.Println(i.Age)  i.Age undefined (type interface{} has no field or method Age)
    
            fmt.Println("
    配列で中身にアクセスできるか確認")
            i = [...]int{0, 1, 2, 3, 4}
            fmt.Println(i)
            // fmt.Println(i[0]) invalid operation: cannot index i (variable of type interface{})
    
            fmt.Println("
    スライスで中身にアクセスできるか確認")
            i = []int{0, 1, 2, 3, 4}
            fmt.Println(i)
            // fmt.Println(i[0]) invalid operation: cannot index i (variable of type interface{})
    
            fmt.Println("
    マップで中身にアクセスできるか確認")
            i = map[int]string{
                    0: "abc",
                    1: "def",
            }
            fmt.Println(i)
            // fmt.Println(i[0]) invalid operation: cannot index i (variable of type interface{})
    
            /*
             * 型アサーションでアクセスできることの確認
             */
            fmt.Println("
    
    構造体にキャストし、中身にアクセスできるか確認")
            i = Person{
                    "tanaka",
                    99,
            }
            person, ok := i.(Person)
            if ok {
                    fmt.Println("person.Name:", person.Name)
            }
    
            fmt.Println("
    配列にキャストし、中身にアクセスできるか確認")
            i = [...]int{0, 1, 2, 3, 4}
            array, ok := i.([5]int)
            if ok {
                    fmt.Println("array[4]:", array[4])
            }
    
            fmt.Println("
    スライスにキャストし、中身にアクセスできるか確認")
            i = []int{0, 1, 2, 3, 4}
            slice, ok := i.([]int)
            if ok {
                    fmt.Println("slice[4]:", slice[4])
            }
    
            fmt.Println("
    マップにキャストし、中身にアクセスできるか確認")
            i = map[int]string{
                    0: "abc",
                    1: "def",
            }
            mp, ok := i.(map[int]string)
            if ok {
                    fmt.Println("mp[0]:", mp[0])
            }
    
            /*
             * 型アサーションでわざとキャストを失敗させる
             */
            fmt.Println("
    
    構造体 -> intにキャストし、戻り値を確認する")
            i = Person{
                    "tanaka",
                    99,
            }
            p, ok := i.(int)
            if ok {
                    fmt.Println("person.Name:", person.Name)
            } else {
                    fmt.Println("キャストに失敗しました p:", p)
            }
    
            fmt.Println("
    配列 -> intにキャストし、戻り値を確認する")
            i = [...]int{0, 1, 2, 3, 4}
            a, ok := i.(int)
            if ok {
                    fmt.Println("array[4]:", array[4])
            } else {
                    fmt.Println("キャストに失敗しました a:", a)
            }
    
            fmt.Println("
    スライス -> intにキャストし、戻り値を確認する")
            i = []int{0, 1, 2, 3, 4}
            s, ok := i.(int)
            if ok {
                    fmt.Println("slice[4]:", slice[4])
            } else {
                    fmt.Println("キャストに失敗しました s:", s)
            }
    
            fmt.Println("
    マップ -> intにキャストし、戻り値を確認する")
            i = map[int]string{
                    0: "abc",
                    1: "def",
            }
            m, ok := i.(int)
            if ok {
                    fmt.Println("mp[0]:", mp[0])
            } else {
                    fmt.Println("キャストに失敗しました m:", m)
            }
    }
    

    执行结果

    構造体で中身にアクセスできるか確認
    {tanaka 99}
    
    配列で中身にアクセスできるか確認
    [0 1 2 3 4]
    
    スライスで中身にアクセスできるか確認
    [0 1 2 3 4]
    
    マップで中身にアクセスできるか確認
    map[0:abc 1:def]
    
    
    構造体にキャストし、中身にアクセスできるか確認
    person.Name: tanaka
    
    配列にキャストし、中身にアクセスできるか確認
    array[4]: 4
    
    スライスにキャストし、中身にアクセスできるか確認
    slice[4]: 4
    
    マップにキャストし、中身にアクセスできるか確認
    mp[0]: abc
    
    
    構造体 -> intにキャストし、戻り値を確認する
    キャストに失敗しました p: 0
    
    配列 -> intにキャストし、戻り値を確認する
    キャストに失敗しました a: 0
    
    スライス -> intにキャストし、戻り値を確認する
    キャストに失敗しました s: 0
    
    マップ -> intにキャストし、戻り値を確認する
    キャストに失敗しました m: 0
    

    类型开关

    与普通开关不同,它通过指定大小写类型进行分支。要评估的表达式就像接口类型变量的“原始类型”。类型是通过接口类型变量 .(type) 获得的。

    句法

    // 戻り値はinterface{}型ではなく、もともとの型に合った値が返る
    switch value := i.(type) {
    case int:
        fmt.Println("iはint型です 値:", value)
    case string:
        fmt.Println("iはstring型です 値:", value)
    default:
        fmt.Println("iはそれ以外です")
    }
    

    示例代码

    package main
    
    import "fmt"
    
    type Person struct {
            Name string
    }
    
    func main() {
    
            var i interface{} = Person{"tanaka"}
    
            switch value := i.(type) {
            case int:
                    fmt.Println("iはint型です 値:", value)
            case string:
                    fmt.Println("iはstring型です 値:", value)
            case Person:
            // 返ってきたvalueはフィールドにアクセスできるためPerson型。interface{}型ではない
                    fmt.Println("iはPerson型です 値:", value.Name)
            default:
                    fmt.Println("iはそれ以外です 値:", value)
            }
    }
    

    执行结果

    iはPerson型です 値: tanaka
    

    综上所述

    目前为止就这样了。

原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308630726.html