【发布时间】:2021-10-01 07:17:50
【问题描述】:
TLDR; 我需要使用指向接口的指针,例如*Comparable 作为Data 的内部对象在我的Node 中作为Tree 的一部分。 Data 应该符合指向Comparable 接口的指针,该接口只有一个方法Less,它比较Comparable 接口类型的两个对象。
如果我在Node 中只使用Comparable 作为Data 的类型,没有指针,一切正常。然而,当我切换到*Comparable 后,编译器给出了奇怪的错误并且代码无法编译
代码Comparable:
package main
type Comparable interface {
Less(than Comparable) bool
}
type Node struct {
Data Comparable
}
func NewNode(data Comparable) *Node {
return &Node{Data: data} }
type Tree struct {
root *Node
}
func NewTree() *Tree {
return &Tree{}
}
func (t *Tree) insert(data Comparable) {
if t.root == nil || t.root.Data.Less(data) {
t.root = NewNode(data)
}
}
type Row struct {
Row []string
}
func NewRow(row[] string) *Row {
return &Row{Row: row}
}
func (r Row) Less(other Comparable) bool {
return r.Row[0] < other.(Row).Row[0]
}
func main() {
t := NewTree()
t.insert(*NewRow([]string{"123"}))
fmt.Printf("%v\n", t.root.Data.(Row).Row)
}
测试:
package main
import (
"reflect"
"testing"
)
func TestInsert(t *testing.T) {
d := []string{"42"}
tree := NewTree()
tree.insert(*NewRow(d))
if !reflect.DeepEqual(tree.root.Data.(Row).Row, d) {
t.Error("returned elements are not matching")
}
}
func TestInsert2x(t *testing.T) {
d1 := []string{"42"}
d2 := []string{"99"}
tree := NewTree()
tree.insert(*NewRow(d1))
tree.insert(*NewRow(d2))
if !reflect.DeepEqual(tree.root.Data.(Row).Row, d2) {
t.Error("returned elements are not matching")
}
}
但是,当我将 Comparable 转换为 *Comparable 时,一切都会中断,根本原因是 *Row is not equal to *Comparable 编译器错误:
对于线return r.Row[0] < other.(*Row).Row[0]
无效类型断言:other.(*Row)(非接口类型 *Comparable on left)
对于线if t.root == nil || t.root.Data.Less(data) {
未解决的参考“少”
package main
type Comparable interface {
Less(than *Comparable) bool
}
type Node struct {
Data *Comparable
}
func NewNode(data *Comparable) *Node {
return &Node{Data: data}
}
type Tree struct {
root *Node
}
func NewTree() *Tree {
return &Tree{}
}
func (t *Tree) insert(data *Comparable) {
if t.root == nil || t.root.Data.Less(data) {
t.root = NewNode(data)
}
}
type Row struct {
Row []string
}
func NewRow(row[] string) *Row {
return &Row{Row: row}
}
func (r *Row) Less(other *Comparable) bool {
return r.Row[0] < other.(*Row).Row[0]
}
func main() {
t := NewTree()
t.insert(NewRow([]string{"123"}))
fmt.Printf("%v\n", t.root.Data.(*Row).Row)
}
测试:
package main
import (
"reflect"
"testing"
)
func TestInsert(t *testing.T) {
d := []string{"42"}
tree := NewTree()
tree.insert(NewRow(d))
if !reflect.DeepEqual(tree.root.Data.(*Row).Row, d) {
t.Error("returned elements are not matching")
}
}
func TestInsert2x(t *testing.T) {
d1 := []string{"42"}
d2 := []string{"99"}
tree := NewTree()
tree.insert(NewRow(d1))
tree.insert(NewRow(d2))
if !reflect.DeepEqual(tree.root.Data.(*Row).Row, d2) {
t.Error("returned elements are not matching")
}
}
问题是如何在Node 中使用*Comparable 作为Data 的类型,以便上面的代码编译。我尝试了几个丑陋的选项,interface{} 类型为Data,并且到处都是显式转换。我不喜欢这种方法,因为它非常不安全。
您可以查看my github repo中的所有代码部分
【问题讨论】:
-
为什么要使用指向接口的指针?在 Go 中,它们几乎从来都不是一个好主意。正如您所发现的,接口已经可以保存指向结构的指针。您说使用常规的
Comparable界面“工作正常”,那您为什么要更改它? -
如果我只在
Node中使用Comparable,这意味着所有Data都被Node复制,当我将它传递给函数或者当我复制、构造或重新创建一棵树时.我想在我的代码中逃避这种应对。 -
用例:您已经在某处创建了巨大的
type Row struct { Row string }对象(而不是上面代码中的slice of strings,只是一个string)。并且您想不惜一切代价避免复制Row字符串。