在Go语言中扩展结构体

4
假设对象A有一个类型为net.Dialer的字段。我想为对象A提供一个自定义实现的net.Dialer,以增强Dial方法。在Go中是否可行?我尝试使用嵌入字段来实现:
package main

import (
    "net"
    "fmt"
)

type dialerConsumer struct {
    dialer net.Dialer
}

func (dc *dialerConsumer) use() error {
    conn, e := dc.dialer.Dial("tcp", "golang.org:http")
    if e != nil {
        return e
    }

    fmt.Printf("conn: %s\n", conn)
    return nil
}

type customDialer struct {
    net.Dialer
}

func main() {
    standardDialer := net.Dialer{}
    consumer := &dialerConsumer{
        dialer: standardDialer,
    }
    consumer.use()


    /*
    customDialer := customDialer{
        net.Dialer{},
    }
    consumer = &dialerConsumer{
        dialer: customDialer,
    }
    consumer.use()
    */
}

然而,当我取消注释 main 中的代码时,我会得到以下编译错误:

src/test.go:38: cannot use customDialer (type customDialer) as type net.Dialer in field value
1个回答

6
你之所以出现这个错误是因为customDialernet.Dialer是两种不同的类型,不能互换使用。在Go中嵌入不同于其他面向对象语言中的类继承,因此无法帮助你实现你想要的目标。

在这种情况下,你可以使用Go接口来实现多态/鸭子类型,由于Go中的接口是隐式满足的,因此你可以定义一个新接口,该接口由一个现有类型来实现,通过具有与新定义接口相同签名的方法来实现。

// already implemented by net.Dialer
type Dialer interface {
    Dial(network, address string) (net.Conn, error)
}

type customDialer struct {
    *net.Dialer
}

func (cd *customDialer) Dial(network, address string) (net.Conn, error) {
    conn, err := cd.Dialer.Dial(network, address)
    if err != nil {
        return nil, err
    }
    fmt.Printf("conn: %s\n", conn)
    return conn, nil
}

// now the dialer field can be set to *customDialer and net.Dialer as well
type dialerConsumer struct {
    dialer Dialer
}

https://play.golang.org/p/i3Vpsh3wii


感谢您的回答,不幸的是,如果我正确理解的话,net.Dialer 被定义为一个结构体而不是接口:https://golang.org/pkg/net/#Dialer 我还应该提到,我无法控制对象 A,因此我不能修改它来使用一个新的接口,该接口可以包括 Dialer 的公共方法 DialDialContext - Paul I
2
如果您无法控制 A,那么您是正确的,您无法将 Dialer 接口分配给它,在 Go 中,除了将 net.Dialer 分配给类型为 net.Dialer 的字段之外,您不能分配任何其他东西... 下一个最好的方法是包装对象 A 并在调用 Dial 之前执行所需的操作。 - mkopriva
是的,我认为你说得对,目前似乎只有将 A 进行包装是我的唯一选择。感谢您的反馈! - Paul I

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接