zhcn 编程语言 Golang Golang 容器 非公開: Go语言中的函数类型实现接口——将函数作为接口调用

Go语言中的函数类型实现接口——将函数作为接口调用

与其他类型一样,函数是“一等公民”。其他类型可以实现接口,函数也可以。本节比较了结构体和函数之间实现接口的过程。

首先,这是本节的完整代码。

 package main

import (
    "fmt"
)

// インボーカーインターフェース
type Invoker interface {
    // Callメソッドを実装する必要があります
    Call(interface{})
}

// 構造体タイプ
type Struct struct {
}

// InvokerのCallを実装する
func (s *Struct) Call(p interface{}) {
    fmt.Println("from struct", p)
}

// 関数を型として定義する
type FuncCaller func(interface{})

// InvokerのCallを実装する
func (f FuncCaller) Call(p interface{}) {

    // f関数本体を呼び出す
    f(p)
}

func main() {

    // インターフェース変数を宣言する
    var invoker Invoker

    // 構造体インスタンスを作成する
    s := new(Struct)

    // インスタンス化された構造体をインターフェイスに割り当てる
    invoker = s

    // インターフェイスを使用してインスタンス化された構造体のメソッドStruct.Callを呼び出します
    invoker.Call("hello")

    // 無名関数をFuncCaller型に変換し、それをインターフェースに割り当てる
    invoker = FuncCaller(func(v interface{}) {
        fmt.Println("from function", v)
    })

    // インターフェースを使用してFuncCaller.Callを呼び出します。内部では、関数本体が呼び出されます。
    invoker.Call("hello")
} 

我有一个这样的界面:


type Invoker interface {
    Call(interface{})
} 

该接口必须实现 Call() 方法。调用时,会传递一个interface{}类型的变量。这种类型的变量代表任何类型的值。

接下来,使用结构体来实现接口。

结构体实现接口

实现Invoker接口的结构体代码如下:

 // Structure Type
type Struct struct {
}

// Invokerの呼び出しを実装する
func (s *Struct) Call(p interface{}) {
    fmt.Println("from struct", p)
} 

代码说明如下:

  • 第二行定义了一个结构体,但本例中的结构体不需要任何成员,主要演示如何实现 Invoker。
  • 第 6 行的 Call() 是该结构的一个方法。该方法的作用是打印struct的值和传递的接口的类型。 {}

实例化定义的Struct类型并将其传递给接口进行调用。这是代码:


var invoker Invoker

s := new(Struct)

invoker = s

invoker.Call("こんにちは") 

代码说明如下:

  • 第 2 行声明了一个 Invoker 类型的变量。
  • 第 5 行,使用 new 实例化结构。该行也可以写为 s:=&Struct。
  • 第8行,对invoker的赋值成功,因为invoker的类型是*Struct,并且Invoker接口类型已经实现。
  • 第11行,通过接口的Call()方法传递hello,此时Struct结构体的Call()方法被调用。

接下来我们就比较一下函数实现结构的差异。

这是代码输出:

from struct こんにちは

函数体实现接口

您不能直接在函数声明中实现接口。将函数定义为类型后,该类型将用于实现结构。当调用类型方法时,必须调用函数体。

 // Function is defined as a type
type FuncCaller func(interface{})

// Implementation of Invoker's Call
func (f FuncCaller) Call(p interface{}) {

    // Call the body of the f() function
    f(p)
} 

代码说明如下:

  • 第二行将 func(interface{}) 定义为 FuncCaller 类型。
  • 在第 5 行中,FuncCaller 的 Call() 方法实现了 Invoker 的 Call() 方法。
  • 第8行,无论func(interface{})如何,都会调用FuncCaller的Call()方法,并且必须手动调用函数体。

上面的代码仅定义了函数的类型,必须由函数本身进行逻辑处理。无需实例化 FuncCaller。您只需将函数转换为 FuncCaller 类型即可。函数的源可以是命名函数、匿名函数或闭包。请参阅下面的代码。

 // Declare interface variable
var invoker Invoker

// Convert anonymous function to FuncCaller type, and then assign it to the interface
invoker = FuncCaller(func(v interface{}) {
    fmt.Println("from function", v)
})

// Use the interface to call FuncCaller.Call, which will invoke the underlying function
invoker.Call("hello") 

代码说明如下:

  • 第二行声明接口变量。
  • 第 5 行将 func(v Interface{}){} 匿名函数转换为 FuncCaller 类型(只能转换函数签名)。在本例中,FuncCaller 类型实现了 Invoker 的 Call() 方法,并且对调用接口的赋值成功。
  • 第 10 行使用接口方法调用。

这是代码输出:

from function hello

HTTP 数据包示例

HTTP包中包含handler接口定义,代码如下:

 type handler interface {
    ServeHTTP(ResponseWriter, *Request)
} 

处理程序用于定义每个 HTTP 请求和响应的处理。

同时,还可以使用处理函数来实现接口。这定义为:


func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

要使用闭包实现默认的 HTTP 请求处理,可以使用 http.HandleFunc() 函数,定义如下:

 func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
} 

DefaultServeMux 是一个 ServeMux 结构,其 HandleFunc() 方法定义如下:

 func (mux *ServeMux) HandleFunc(pattern string, handler func
(ResponseWriter, *Request)) {
    mux.Handle(pattern, HandlerFunc(handler))
}

上面的代码将外部传递的函数handler()转换为HandlerFunc类型。 HandlerFunc 类型实现了 Handler 的 ServeHTTP 方法。底层可以使用不同类型实现Handler接口进行处理。

通俗易懂的讲解《Go语言的函数类型实现接口——将函数作为接口来调用》!您必须观看的最佳 2 个视频

GO言語でAPI開発「 gRPC 」入門
https://www.youtube.com/watch?v=vliAVKYELy8&pp=ygWIASBHbyDoqIDoqp7jga7plqLmlbDlnovjga_jgqTjg7Pjgr_jg7zjg5XjgqfjgqTjgrnjgpLlrp_oo4XjgZfjgb7jgZkgLSDplqLmlbDjgpLjgqTjg7P jgr_jg7zjg5XjgqfjgqTjgrnjgajjgZfjgablkbzjgbPlh7rjgZfjgb7jgZkmaGw9SkE%3D
22 Golang チュートリアル – インターフェイス
https://www.youtube.com/watch?v=yBimXxbjQuI&pp=ugMICgJqYRABGAHKBYgBIEdvIOiogOiqnuOBrumWouaVsOWei-OBr-OCpOODs-OCv-ODvOODleOCp-OCpOOCueOCkuWun-ijheOBl-OBvuOBmSAtIOmWouaVsOOCkuOCpOODs-OCv-ODvOOD leOCp- OCpOOCueOBqOOBl-OBpuWRvoOBs-WHuuOBl-OBvuOBmSZobD1KQQ%3D%3D
与其他类型一样,函数是“一等公民”。其他类型可以实现接口,函数也可以。本节比较了结构体和函数之间实现接口的过程。

首先,这是本节的完整代码。

 package main

import (
    "fmt"
)

// インボーカーインターフェース
type Invoker interface {
    // Callメソッドを実装する必要があります
    Call(interface{})
}

// 構造体タイプ
type Struct struct {
}

// InvokerのCallを実装する
func (s *Struct) Call(p interface{}) {
    fmt.Println("from struct", p)
}

// 関数を型として定義する
type FuncCaller func(interface{})

// InvokerのCallを実装する
func (f FuncCaller) Call(p interface{}) {

    // f関数本体を呼び出す
    f(p)
}

func main() {

    // インターフェース変数を宣言する
    var invoker Invoker

    // 構造体インスタンスを作成する
    s := new(Struct)

    // インスタンス化された構造体をインターフェイスに割り当てる
    invoker = s

    // インターフェイスを使用してインスタンス化された構造体のメソッドStruct.Callを呼び出します
    invoker.Call("hello")

    // 無名関数をFuncCaller型に変換し、それをインターフェースに割り当てる
    invoker = FuncCaller(func(v interface{}) {
        fmt.Println("from function", v)
    })

    // インターフェースを使用してFuncCaller.Callを呼び出します。内部では、関数本体が呼び出されます。
    invoker.Call("hello")
} 

我有一个这样的界面:


type Invoker interface {
    Call(interface{})
} 

该接口必须实现 Call() 方法。调用时,会传递一个interface{}类型的变量。这种类型的变量代表任何类型的值。

接下来,使用结构体来实现接口。

结构体实现接口

实现Invoker接口的结构体代码如下:

 // Structure Type
type Struct struct {
}

// Invokerの呼び出しを実装する
func (s *Struct) Call(p interface{}) {
    fmt.Println("from struct", p)
} 

代码说明如下:

  • 第二行定义了一个结构体,但本例中的结构体不需要任何成员,主要演示如何实现 Invoker。
  • 第 6 行的 Call() 是该结构的一个方法。该方法的作用是打印struct的值和传递的接口的类型。 {}

实例化定义的Struct类型并将其传递给接口进行调用。这是代码:


var invoker Invoker

s := new(Struct)

invoker = s

invoker.Call("こんにちは") 

代码说明如下:

  • 第 2 行声明了一个 Invoker 类型的变量。
  • 第 5 行,使用 new 实例化结构。该行也可以写为 s:=&Struct。
  • 第8行,对invoker的赋值成功,因为invoker的类型是*Struct,并且Invoker接口类型已经实现。
  • 第11行,通过接口的Call()方法传递hello,此时Struct结构体的Call()方法被调用。

接下来我们就比较一下函数实现结构的差异。

这是代码输出:

from struct こんにちは

函数体实现接口

您不能直接在函数声明中实现接口。将函数定义为类型后,该类型将用于实现结构。当调用类型方法时,必须调用函数体。

 // Function is defined as a type
type FuncCaller func(interface{})

// Implementation of Invoker's Call
func (f FuncCaller) Call(p interface{}) {

    // Call the body of the f() function
    f(p)
} 

代码说明如下:

  • 第二行将 func(interface{}) 定义为 FuncCaller 类型。
  • 在第 5 行中,FuncCaller 的 Call() 方法实现了 Invoker 的 Call() 方法。
  • 第8行,无论func(interface{})如何,都会调用FuncCaller的Call()方法,并且必须手动调用函数体。

上面的代码仅定义了函数的类型,必须由函数本身进行逻辑处理。无需实例化 FuncCaller。您只需将函数转换为 FuncCaller 类型即可。函数的源可以是命名函数、匿名函数或闭包。请参阅下面的代码。

 // Declare interface variable
var invoker Invoker

// Convert anonymous function to FuncCaller type, and then assign it to the interface
invoker = FuncCaller(func(v interface{}) {
    fmt.Println("from function", v)
})

// Use the interface to call FuncCaller.Call, which will invoke the underlying function
invoker.Call("hello") 

代码说明如下:

  • 第二行声明接口变量。
  • 第 5 行将 func(v Interface{}){} 匿名函数转换为 FuncCaller 类型(只能转换函数签名)。在本例中,FuncCaller 类型实现了 Invoker 的 Call() 方法,并且对调用接口的赋值成功。
  • 第 10 行使用接口方法调用。

这是代码输出:

from function hello

HTTP 数据包示例

HTTP包中包含handler接口定义,代码如下:

 type handler interface {
    ServeHTTP(ResponseWriter, *Request)
} 

处理程序用于定义每个 HTTP 请求和响应的处理。

同时,还可以使用处理函数来实现接口。这定义为:


func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

要使用闭包实现默认的 HTTP 请求处理,可以使用 http.HandleFunc() 函数,定义如下:

 func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
} 

DefaultServeMux 是一个 ServeMux 结构,其 HandleFunc() 方法定义如下:

 func (mux *ServeMux) HandleFunc(pattern string, handler func
(ResponseWriter, *Request)) {
    mux.Handle(pattern, HandlerFunc(handler))
}

上面的代码将外部传递的函数handler()转换为HandlerFunc类型。 HandlerFunc 类型实现了 Handler 的 ServeHTTP 方法。底层可以使用不同类型实现Handler接口进行处理。

通俗易懂的讲解《Go语言的函数类型实现接口——将函数作为接口来调用》!您必须观看的最佳 2 个视频

GO言語でAPI開発「 gRPC 」入門
https://www.youtube.com/watch?v=vliAVKYELy8&pp=ygWIASBHbyDoqIDoqp7jga7plqLmlbDlnovjga_jgqTjg7Pjgr_jg7zjg5XjgqfjgqTjgrnjgpLlrp_oo4XjgZfjgb7jgZkgLSDplqLmlbDjgpLjgqTjg7P jgr_jg7zjg5XjgqfjgqTjgrnjgajjgZfjgablkbzjgbPlh7rjgZfjgb7jgZkmaGw9SkE%3D
22 Golang チュートリアル – インターフェイス
https://www.youtube.com/watch?v=yBimXxbjQuI&pp=ugMICgJqYRABGAHKBYgBIEdvIOiogOiqnuOBrumWouaVsOWei-OBr-OCpOODs-OCv-ODvOODleOCp-OCpOOCueOCkuWun-ijheOBl-OBvuOBmSAtIOmWouaVsOOCkuOCpOODs-OCv-ODvOOD leOCp- OCpOOCueOBqOOBl-OBpuWRvoOBs-WHuuOBl-OBvuOBmSZobD1KQQ%3D%3D