Golang中匿名接口的实现

o7jaxewo  于 2022-12-16  发布在  Go
关注(0)|答案(4)|浏览(234)

在Go语言中,有没有一种方法可以匿名地满足一个接口?看起来没有,但这是我最好的尝试。
(In Playground

package main

import "fmt"

type Thing interface {
    Item() float64
    SetItem(float64)
}

func newThing() Thing {
    item := 0.0
    return struct {
        Item (func() float64)
        SetItem (func(float64))
    }{
        Item: func() float64 { return item },
        SetItem: func(x float64) { item = x },
    }
}

func main() {
    thing := newThing()
    fmt.Println("Hello, playground")
    fmt.Println(thing)
}
5kgi1eie

5kgi1eie1#

Go语言使用方法集来声明哪些方法属于一个类型,只有一种方法可以声明接收方类型(方法)的函数:

func (v T) methodName(...) ... { }

因为嵌套函数是被禁止的,所以无法在匿名结构上定义方法集。
第二点是方法是只读的,引入方法值是为了允许传递方法并在goroutine中使用它们,但不允许操作方法集。
您可以做的是提供一个ProtoThing并引用匿名结构体(on play)的底层实现:

type ProtoThing struct { 
    itemMethod func() float64
    setItemMethod func(float64)
}

func (t ProtoThing) Item() float64 { return t.itemMethod() }
func (t ProtoThing) SetItem(x float64) { t.setItemMethod(x) }

// ...

t := struct { ProtoThing }{}

t.itemMethod = func() float64 { return 2.0 }
t.setItemMethod = func(x float64) { item = x }

这是因为通过嵌入ProtoThing继承了方法集,因此匿名结构体也满足Thing接口。

n3ipq98p

n3ipq98p2#

下面是用匿名函数满足接口的简洁方法。

type Thinger interface {
    DoThing()
}

type DoThingWith func()

// Satisfy Thinger interface.
// So we can now pass an anonymous function using DoThingWith, 
// which implements Thinger.
func (thing DoThingWith) DoThing() {
    // delegate to the anonymous function
    thing()
}

type App struct {
}

func (a App) DoThing(f Thinger) {
    f.DoThing()
}

//...Somewhere else in your code:
app := App{}

// Here we use an anonymous function which satisfies the interface
// The trick here is to convert the anonymous function to the DoThingWith type
// which delegates to the anonymous function

app.DoThing(DoThingWith(func() {
    fmt.Println("Hey interface, are you satisfied?")
}))

Playground:https://play.golang.org/p/k8_X9g2NYc
nb,看起来http包中的HandlerFunc使用了这个模式:https://golang.org/pkg/net/http/#HandlerFunc
编辑:为清晰起见,将类型DoThing更改为DoThingWith。更新Playground

hgc7kmma

hgc7kmma3#

你不能用方法示例化一个结构体,它们需要被声明为函数,但是在Go语言中函数是“第一类公民”,所以它们可以像在JavaScript中一样是字段值(但是有类型)。
您可以创建一个接受func字段的泛型结构来实现该接口:

package main

import "fmt"

type Thing interface {
    Item() float64
    SetItem(float64)
}

// Implements Thing interface
type thingImpl struct {
    item    func() float64
    setItem func(float64)
}
func (i thingImpl) Item() float64     { return i.item() }
func (i thingImpl) SetItem(v float64) { i.setItem(v) }

func newThing() Thing {
    item := 0.0
    return thingImpl{
        item:    func() float64 { return item },
        setItem: func(x float64) { item = x },
    }
}

func main() {
    thing := newThing()
    fmt.Println("Hello, playground")
    fmt.Println(thing)
}
3vpjnl9f

3vpjnl9f4#

我是在研究典型的http中间件实现如何返回一个http.Handler接口,而不为它返回的匿名函数定义一个ServeHTTP方法时想到这里的。

func LoggingMiddleware(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Method, r.URL.String())
        next.ServeHTTP(w, r)
    }
    return http.HandlerFunc(fn)
}

这里,匿名函数被转换为HandlerFunc类型以满足接口要求:http.HandlerFunc(fn)
尽管匿名函数并不通过实现ServeHTTP方法直接实现Handler接口本身,但它转换成的HandlerFunc类型确实实现了ServeHTTP方法。

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

下面是一个简单的操场例子:https://play.golang.org/p/JX0hrcXyj6Q

package main

import (
    "fmt"
)

type Walker interface {
    Walk() // interface to be fulfilled by anonymous function
}

type WalkerFunc func()

// Walk method satisfies Walker interface
func (wf WalkerFunc) Walk() {
    fmt.Println("start walking")
    wf()
    fmt.Printf("stop walking\n\n")
}

func main() {
    // use type conversion to convert anonymous function to WalkerFunc type, satisfying Walker interface
    WalkerFunc(func() { fmt.Println("chew gum") }).Walk()
    WalkerFunc(func() { fmt.Println("smell roses") }).Walk()
}

/*
OUTPUT:
start walking
chew gum
stop walking

start walking
smell roses
stop walking
*/

相关问题