在不同结构之间共享方法实现

问题描述 投票:0回答:2

假设我们有 2 个结构体共享一个属性,具有相同的名称和用途,但大小不同:

type (
    L16 struct {
        Length uint16
    }

    L32 struct {
        Length uint32
    }
)

目标是使这些结构体具有具有完全相同的签名和实现的

GetLength
方法:

func (h *L16) GetLength() int {
    return int(h.Length)
}

func (h *L32) GetLength() int {
    return int(h.Length)
}

—但要避免对每个结构重复实现。

所以我尝试:

type (

    LengthHolder interface {
        GetLength() int
    }

    LengthHolderStruct struct {
        LengthHolder
    }

    L16 struct {
        LengthHolderStruct
        Length uint16
    }

    L32 struct {
        LengthHolderStruct
        Length uint32
    }

)

func (h *LengthHolderStruct) GetLength() int {
    return int(h.Length)
}

— 但是

h.Length undefined (type *LengthHolderStruct has no field or method Length)
会出现错误。

我们该怎么做?

go dry composition go-interface
2个回答
3
投票

转到 1.17 及以下版本

毫不客气的回答是:你不能你不应该。只需在每个结构上实现该方法即可让未来的您和其他维护者感到高兴。

无论如何,假设您绝对必须这样做,当然 embedded 类型对 embedding 类型一无所知,因此您无法从

Length
引用
LengthHolderStruct

就个人而言,我认为@mh-cbon答案是一个不错的妥协。为了提供替代方案,您可以通过将 Length 字段声明为嵌入式结构上的

interface{}
并使用类型开关(将类型安全扔进垃圾箱),以一种
非常难看
的方式解决这个问题。

我不会在我的生产系统中使用以下代码,但你可以这样做:

func main() {
    l16 := L16{
        LengthHolderStruct: LengthHolderStruct{
            Length: uint16(200), 
            // but nothing stops you from setting uint32(200)
        },
    }
    fmt.Println(l16.GetLength())
}

type (
    LengthHolder interface {
        GetLength() int
    }

    LengthHolderStruct struct {
        Length interface{}
    }

    L16 struct {
        LengthHolderStruct
    }

    L32 struct {
        LengthHolderStruct
    }
)

func (h *LengthHolderStruct) GetLength() int {
    switch t := h.Length.(type) {
    case uint16:
        return int(t)
    case uint32:
        return int(t)
    }
    return 0
}

转到1.18及以上版本

使用泛型。只要

Constraint
中的类型都可以转换为
int
,就可以使用以下代码:

type Constraint interface {
     ~uint16 | ~uint32
}

type LX[T Constraint] struct {
    Length T
}

func (h *LX[T]) GetLength() int {
    return int(h.Length)
}

func main() {
    lx := LX[uint16]{
        Length: uint16(200),
    }
    fmt.Println(lx.GetLength()) // 200
}

去游乐场:https://go.dev/play/p/LYbDrjQkgCN


0
投票

我也遇到了同样的问题,但我意识到我处理问题的方式是错误的。 Golang 不是面向对象的语言,您不应该这样对待它,您可以重用接受结构泛型的函数的方法。这应该可以解决问题。按照语言设计的使用方式来对待它

© www.soinside.com 2019 - 2024. All rights reserved.