Extend struct in Go

huangapple go评论85阅读模式
英文:

Extend struct in Go

问题

假设对象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
英文:

Suppose object A has a field of type net.Dialer. I'd like to provide object A with a custom implementation of net.Dialer that augments the Dial method. Is this doable in Go? I'm trying to use embedded fields like so:

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()
    */
}

However, when I uncomment the commented-out code in main, I get the following compilation error:

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

答案1

得分: 6

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

在这种情况下,你可以使用Go语言的接口来实现类似多态/鸭子类型的功能。由于Go语言中的接口是隐式满足的,你可以定义一个新的接口,只要现有类型具有与新定义接口相同签名的方法,它就会自动实现该接口。

// 已经由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
}

// 现在dialer字段可以设置为*customDialer和net.Dialer
type dialerConsumer struct {
    dialer Dialer
}

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

英文:

You're getting the error because customDialer and net.Dialer are two different types and cannot be used interchangeably. Embedding in Go is not the same as class inheritance in other OO langauges so it won't help you with what you trying to do.

What you can do instead in this case is to use Go interfaces which give you something like polymorphism/duck-typing, and since interfaces in Go are satified implicitly you can define a new interface that an existing type will implement by virtue of having a method with the same signature as the newly defined interface.

// 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

huangapple
  • 本文由 发表于 2017年3月27日 18:43:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/43044224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定