データ構造とアルゴリズム(Golang実装)(5)Golangインターフェースの簡単な紹介

インターフェース

ではGolang世界では、と呼ばれるものがあるinterface何かが、それは素晴らしいです、。

まず、データ型インターフェイス{}

変数が整数であるか文字列であるかにかかわらず、変数のデータ型が以前はわからないが、それでも使用したい場合。

Golang「名前」と呼ばれるinterface{}データ型が生成され、それがどの型であるかが不明であることを示します。例:

package main

import (
    "fmt"
    "reflect"
)

func print(i interface{}) {
    fmt.Println(i)
}

func main() {
    // 声明一个未知类型的 a,表明不知道是什么类型
    var a interface{}
    a = 2
    fmt.Printf("%T,%v\n", a, a)

    // 传入函数
    print(a)
    print(3)
    print("i love you")

    // 使用断言,判断是否是 int 数据类型
    v, ok := a.(int)
    if ok {
        fmt.Printf("a is int type,value is %d\n", v)
    }

    // 使用断言,判断变量类型
    switch a.(type) {
    case int:
        fmt.Println("a is type int")
    case string:
        fmt.Println("a is type string")
    default:
        fmt.Println("a not type found type")
    }

    // 使用反射找出变量类型
    t := reflect.TypeOf(a)
    fmt.Printf("a is type: %s", t.Name())
}

出力:

int,2
2
3
i love you
a is int type,value is 2
a is type int
a is type: int

1.1。基本的な使用法

interface{}未知の型の変数を宣言するために使用しますa

    // 声明一个未知类型的 a,表明不知道是什么类型
    var a interface{}
    a = 2
    fmt.Printf("%T,%v\n", a, a)

次に、変数に整数を割り当てます。a=2現時点aではそれはまだ不明なタイプです。プレースホルダー%T使用して変数の実際のタイプを出力し、プレースホルダー使用し%vて値を出力します。このときfmt.Printf、タイプは内部的に判断されます。

関数のパラメーターをinterface変数の定義と同じように設定することもできます。

func print(i interface{}) {
    fmt.Println(i)
}

使用する場合:

    // 传入函数
    print(a)
    print(3)
    print("i love you")

print関数に渡すパラメーター、整数3や文字列など、任意の型にすることができますi love you関数を入力すると、関数内の変数はi型を失い、不明な型になります。この機能により、異なるタイプのデータを処理する場合に複数の関数を記述する必要がなくなります。

もちろん、構造内のフィールドも次のようになりますinterface{}

type H struct {
    A interface{}
    B interface{}
}

1.2。特定のタイプを決定する

定義しましたinterface{}が、実際の使用にあたっては、タイプを判断する必要があります。判断には2つの方法があります。

アサーションを使用:

    // 使用断言,判断是否是 int 数据类型
    v, ok := a.(int)
    if ok {
        fmt.Printf("a is int type,value is %d\n", v)
    }

変数の直後に使用すると.(int)、2つの戻り値v, okが返されます。それが本当に整数型であるokことをtrue示している場合、この整数が割り当てられv、私たちはv楽しく遊ぶことができます。それ以外の場合は、okのようにfalsev0のデフォルト値であるNULL値に。

我々はすべてのケースで使用する場合は、ので、厳しいものにinterface{}変数の型、データ型があるかもしれない.(int)、かもしれない.(string)、使用することができますswitch簡単にするために:

    // 使用断言,判断变量类型
    switch a.(type) {
    case int:
        fmt.Println("a is type int")
    case string:
        fmt.Println("a is type string")
    default:
        fmt.Println("a not type found type")
    }

ではではswicth、アサーションは、もはや使用されていない.(具体类型)、しかしa.(type)

最後に、リフレクションパッケージreflectを使用してデータ型を決定する方法があります

    // 使用反射找出变量类型
    t := reflect.TypeOf(a)
    fmt.Printf("a is type: %s", t.Name())

このパッケージは、非セキュアポインターを直接使用して、実際のデータ型を取得します。

func TypeOf(i interface{}) Type {
    eface := *(*emptyInterface)(unsafe.Pointer(&i))
    return toType(eface.typ)
}

一般的な日常の開発では、リフレクションパッケージはほとんど使用されません。

2.インターフェース構造

私たちはみな関数型プログラミングか構造型メソッドプログラミングですが、他の言語に特徴的なオブジェクト指向、オブジェクト継承はありませんか?はい、Golang言語はインターフェイス指向プログラミングと呼ばれています。

package main

import (
    "fmt"
    "reflect"
)

// 定义一个接口,有一个方法
type A interface {
    Println()
}

// 定义一个接口,有两个方法
type B interface {
    Println()
    Printf() int
}

// 定义一个结构体
type A1Instance struct {
    Data string
}

// 结构体实现了Println()方法,现在它是一个 A 接口
func (a1 *A1Instance) Println() {
    fmt.Println("a1:", a1.Data)
}

// 定义一个结构体
type A2Instance struct {
    Data string
}

// 结构体实现了Println()方法,现在它是一个 A 接口
func (a2 *A2Instance) Println() {
    fmt.Println("a2:", a2.Data)
}

// 结构体实现了Printf()方法,现在它是一个 B 接口,它既是 A 又是 B 接口
func (a2 *A2Instance) Printf() int {
    fmt.Println("a2:", a2.Data)
    return 0
}

func main() {
    // 定义一个A接口类型的变量
    var a A

    // 将具体的结构体赋予该变量
    a = &A1Instance{Data: "i love you"}
    // 调用接口的方法
    a.Println()
    // 断言类型
    if v, ok := a.(*A1Instance); ok {
        fmt.Println(v)
    } else {
        fmt.Println("not a A1")
    }
    fmt.Println(reflect.TypeOf(a).String())

    // 将具体的结构体赋予该变量
    a = &A2Instance{Data: "i love you"}
    // 调用接口的方法
    a.Println()
    // 断言类型
    if v, ok := a.(*A1Instance); ok {
        fmt.Println(v)
    } else {
        fmt.Println("not a A1")
    }
    fmt.Println(reflect.TypeOf(a).String())

    // 定义一个B接口类型的变量
    var b B
    //b = &A1Instance{Data: "i love you"} // 不是 B 类型
    b = &A2Instance{Data: "i love you"}
    fmt.Println(b.Printf())
}

出力:

a1: i love you
&{i love you}
*main.A1Instance
a2: i love you
not a A1
*main.A2Instance
a2: i love you
0

インターフェイスタイプを定義できます。使用するtype 接口名 interfaceと、今回は次のようになりませんinterface{}

// 定义一个接口,有一个方法
type A interface {
    Println()
}

// 定义一个接口,有两个方法
type B interface {
    Println()
    Printf() int
}

これは、インターフェースことが分かるAB限り構造がされると、各インターフェイスが多数の方法を有し、抽象的構造であるstructこれらのメソッドを実装し、これらは、インターフェースのこのタイプの構造です。など:

// 定义一个结构体
type A1Instance struct {
    Data string
}

// 结构体实现了Println()方法,现在它是一个 A 接口
func (a1 *A1Instance) Println() {
    fmt.Println("a1:", a1.Data)
}

// 定义一个结构体
type A2Instance struct {
    Data string
}

// 结构体实现了Println()方法,现在它是一个 A 接口
func (a2 *A2Instance) Println() {
    fmt.Println("a2:", a2.Data)
}

// 结构体实现了Printf()方法,现在它是一个 B 接口,它既是 A 又是 B 接口
func (a2 *A2Instance) Printf() int {
    fmt.Println("a2:", a2.Data)
    return 0
}

構造体に特定のメソッドを実装する必要があるため、インターフェース型の変数を定義して、それに構造体を割り当てることができます。

    // 定义一个A接口类型的变量
    var a A
    // 将具体的结构体赋予该变量
    a = &A1Instance{Data: "i love you"}
    // 调用接口的方法
    a.Println()

構造がこのメソッドを実装していない場合、コンパイルは失敗し、バイナリはコンパイルできません。

もちろん、アサーションとリフレクションを使用して、インターフェイスタイプが属する実際の構造を判別することもできますstruct

    // 断言类型
    if v, ok := a.(*A1Instance); ok {
        fmt.Println(v)
    } else {
        fmt.Println("not a A1")
    }
    fmt.Println(reflect.TypeOf(a).String())

Golang構造体がインターフェイスメソッドを実装しているかどうかを判断するのは非常に賢明です。実装されている場合、構造体はインターフェイスタイプです。インターフェース構造の特徴を柔軟に活かし、組み合わせた形でより柔軟なプログラムを開発します。

シリーズ記事エントリー

私は、スター陳思い、私が個人的に書かれているようこそ(Golangが達成)のデータ構造とアルゴリズムの記事で始まる、より親しみやすいGitBookを読むために

元の記事を13件公開しました 賞賛されました0 訪問94

おすすめ

転載: blog.csdn.net/m0_46803965/article/details/105563303