Golang中实现多态结构体字段的方法
Golang中实现多态结构体字段的方法 (刚接触Go语言)
我想创建一个结构体字段,它可以持有指向两种不同类型结构体的指针。示例:
type Letter struct {
...
Previous *Character // 这是无效的,我没有这个类型,这只是一个示例
}
type Punct struct {
...
Previous *Character // 这是无效的,我没有这个类型,这只是一个示例
}
l1 := Letter{}
l2 := Letter{ Previous: &l1, }
p1 := Punct{ Previous: &l2, }
p2 := Punct{ Previous: &p1, }
这个想法(简化版)是:一个字符串由字符组成,字符可以是字母或标点符号(不,我不能在这里使用rune类型,因为每个结构体都包含一些我需要与每个字符关联的其他有用信息)。每个字符都有一个指向前一个字符的引用——因此有了Previous字段。如你所见,在每个结构体中,Previous应该被赋值为指向不同类型结构体或相同类型结构体的指针。
但我不确定在这里如何处理多态性,以及Previous字段应该声明为什么类型。接口在这里似乎没有意义,因为它们处理的是方法,而不是字段类型。你会如何处理这个问题?
更多关于Golang中实现多态结构体字段的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
您可以使用泛型来实现相同的功能,而无需使用 any。
// 示例代码
泛型?这是一个不错的方法,但你也需要为这个场景定义一个接口作为约束。如果这只是一个示例,我可能不会使用泛型,而是尝试将其泛化和抽象成接口,在我看来这样更具可扩展性。当然,具体问题需要具体分析,这只是我的个人观点。
哦,谢谢,这看起来非常明显。唯一的问题是,它的扩展性不太好,并且我决定添加的每个新结构体都需要在 Character 结构体中添加一个额外的字段。我想知道是否有其他方法可以实现相同的目标(我希望可能只是我对接口的理解不足,存在一个涉及接口的解决方案)。
type Character sturct {
Pre *Character
Letter * Letter
Punct * Punct
}
l1:=Character{Letter:&Letter{}}
l2:=Character{Pre:&l1,Letter:&Letter{}}
p1:=Character{Pre:&l2,Punct:&Punct{}}
p2:=Character{Pre:&p1,Punct:&Punct{}}
应该将什么视为一个单一的元素?至于这个单元格是字母还是符号,这是该单元的一个属性。
type Character interface {
Pre()Character
...
}
type Letter struct {
Previous Character
}
func(l *Letter)Pre()Character{
returen l.Previous
}
type Punct struct {
Previous Character
}
func(p *Punct)Pre()Character{
returen p.Previous
}
我认为你并不理解接口是什么。
any只是一个简单的接口类型,我这里只是用any来举例。实际上,你应该做的是类似这样的事情。
type Letter struct {
Previous any
}
type Punct struct {
Previous any
}
l1 := Letter{}
l2 := Letter{ Previous: &l1, }
p1 := Punct{ Previous: &l2, }
p2 := Punct{ Previous: &p1, }
// 像这样,但要调用它,必须像这样:
l,ok:=p1.Previous.(*Letter)
if ok{
}
这只是一个使用 any 来表示接口的简单示例,实际上会添加一些特定的方法来避免其他结构体类型实现该接口,从而造成代码混乱。
是的。我考虑过使用 any,虽然那似乎有点宽泛。我不需要对类型特别严格,但我想,如果能理解如何在 Go 中实现类似 OOP 风格的多态和继承,也不会有什么坏处,就像这样(伪 OOP 代码):
class Character { ... }
class Letter extends Character {
previous Character
}
class Punct extends Character {
previous Character
}
l1 = new Letter();
l2 = new Letter();
p1 = new Punct();
p2 = new Punct();
l2.previous = l1;
p1.previous = l2;
p2.previous = p1;
这段代码将 previous 字段限制为 Character 派生类的实例。
在Go中实现多态结构体字段的典型方法是使用接口。虽然你提到接口通常用于方法,但它们同样可以定义字段类型,因为接口类型可以持有任何实现了该接口的值。以下是解决方案:
首先定义一个包含所需方法的接口,然后让结构体实现该接口:
type Character interface {
GetType() string
// 可以添加其他需要的方法
}
type Letter struct {
Content string
Previous Character // 使用接口类型
}
type Punct struct {
Symbol string
Previous Character // 使用接口类型
}
// 实现Character接口的方法
func (l Letter) GetType() string {
return "letter"
}
func (p Punct) GetType() string {
return "punct"
}
现在你可以创建链式结构:
l1 := Letter{Content: "A"}
l2 := Letter{Content: "B", Previous: l1}
p1 := Punct{Symbol: "!", Previous: l2}
p2 := Punct{Symbol: "?", Previous: p1}
如果需要存储指针,可以这样调整:
type Letter struct {
Content string
Previous Character
}
type Punct struct {
Symbol string
Previous Character
}
l1 := &Letter{Content: "A"}
l2 := &Letter{Content: "B", Previous: l1}
p1 := &Punct{Symbol: "!", Previous: l2}
p2 := &Punct{Symbol: "?", Previous: p1}
如果需要访问具体类型,可以使用类型断言:
func processPrevious(char Character) {
switch v := char.(type) {
case *Letter:
fmt.Printf("Previous is Letter: %s\n", v.Content)
case *Punct:
fmt.Printf("Previous is Punct: %s\n", v.Symbol)
default:
fmt.Println("Unknown type")
}
}
// 使用
processPrevious(p2.Previous) // 输出: Previous is Punct: !
如果不需要方法,可以使用空接口interface{}(或Go 1.18+的any):
type Letter struct {
Content string
Previous any
}
type Punct struct {
Symbol string
Previous any
}
l1 := &Letter{Content: "A"}
l2 := &Letter{Content: "B", Previous: l1}
p1 := &Punct{Symbol: "!", Previous: l2}
p2 := &Punct{Symbol: "?", Previous: p1}
但推荐使用具体接口,因为它提供了类型安全。


