dom*_*ato 10 interface linked-list go comparison-operators
我正在golang中进行一个简单的链表实现,用于学习目的.元素的定义如下:
type Element struct {
next, prev *Element
Value interface{}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,Value可以是满足空接口的任何东西.现在,作为一个新功能,我想这样做,当你在列表中插入一个新元素时,它会以排序的方式插入它 - 每个元素将<=下一个.
为了做到这一点,我写了以下方法:
func (l *LinkedList) Add(val interface{}) *Element {
this := &l.Root
e := Element{Value: val}
for {
if this.next.Value != nil && this.next.Value < val { // <-comparison here
this = this.next
} else {
return l.insert(&e, this)
}
}
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨operator < not defined on interface
哪个是公平的.所以我理解在我的Element typedef中,我应该将Value限制为可以使用<
运算符进行比较的类型.我在研究golang不支持运算符重载的问题时学到了这一点 - 我不是想这样做.相反,我只是想确保Element.Value是一个可以使用<
运算符进行比较的类型.我该怎么做呢?
在我看来,简单地定义基于内置的新类型可能并不困难,可以通过某种功能进行比较.所以我写了这个烂摊子(以及其他尝试做同样事情的方法):
type Comparable interface {
LessThan(j interface{}) bool // tried (j Comparable), (j MyInt), etc
EqualTo(j interface{}) bool // tried (j Comparable), (j MyInt), etc
}
type MyInt int
func (i MyInt) LessThan(j MyInt) bool {
return i < j
}
func (i MyInt) EqualTo(j MyInt) bool {
return i == j
}
type Element struct {
next, prev *Element
Value Comparable
}
Run Code Online (Sandbox Code Playgroud)
我真正想要的是定义一个接口,如果为一个类型实现,它提供了函数,LessThan
并EqualTo
在该类型的两个实例上运行并提供了一个bool - 类似的东西LessThan(i, j WhatEvers) bool
可以用来代替<
.我在下面意识到它是作为实例方法实现的 - 我已经尝试了两种方式但没有成功.有了上面的内容,我会this.next.Value.LessThan(val)
在Add函数中使用它:我得到:
linkedlist.MyInt does not implement linkedlist.Comparable (wrong type for EqualTo method)
have EqualTo(linkedlist.MyInt) bool
want EqualTo(interface {}) bool
Run Code Online (Sandbox Code Playgroud)
要么
linkedlist.MyInt does not implement linkedlist.Comparable (wrong type for EqualTo method)
have EqualTo(linkedlist.MyInt) bool
want EqualTo(linkedlist.Comparable) bool
Run Code Online (Sandbox Code Playgroud)
是否可以使用接口来要求必须存在一个在自定义类型的两个实例上运行的特定函数,或者仅用于方法?
小智 5
编辑:
考虑这个用户类型:
type userType struct {
frequency int
value rune
}
Run Code Online (Sandbox Code Playgroud)
并假设您想将此类型添加到您的链接列表中:
并且它应该首先按频率排序,然后如果频率相同,请查看字符值。所以Compare
函数将是:
func (a userType) Compare(b userType) int {
if a.frequency > b.frequency {
return 1
}
if a.frequency < b.frequency {
return -1
}
if a.value > b.value {
return 1
}
if a.value < b.value {
return -1
}
return 0
}
Run Code Online (Sandbox Code Playgroud)
满足这个接口:
type Comparer interface {
Compare(b userType) int
}
Run Code Online (Sandbox Code Playgroud)
现在将这些{1,'d'} {2,'b'} {3,'c'} {4,'a'} {4,'b'} {4,'c'}
类型添加到 LinkeList:
示例代码:
package main
import (
"container/list"
"fmt"
)
type Comparer interface {
Compare(b userType) int
}
type userType struct {
frequency int
value rune
}
// it should sort by frequency first, then if the frequencies are the same, look at the char value.
func (a userType) Compare(b userType) int {
if a.frequency > b.frequency {
return 1
}
if a.frequency < b.frequency {
return -1
}
if a.value > b.value {
return 1
}
if a.value < b.value {
return -1
}
return 0
}
func Insert(val userType, l *list.List) {
e := l.Front()
if e == nil {
l.PushFront(val)
return
}
for ; e != nil; e = e.Next() {
var ut userType = e.Value.(userType)
if val.Compare(ut) < 0 {
l.InsertBefore(val, e)
return
}
}
l.PushBack(val)
}
func main() {
l := list.New()
Insert(userType{4, 'c'}, l)
Insert(userType{4, 'a'}, l)
Insert(userType{4, 'b'}, l)
Insert(userType{2, 'b'}, l)
Insert(userType{3, 'c'}, l)
Insert(userType{1, 'd'}, l)
for e := l.Front(); e != nil; e = e.Next() {
ut := e.Value.(userType)
fmt.Printf("{%d,%q} ", ut.frequency, ut.value)
}
fmt.Println()
var t interface{} = userType{4, 'c'}
i, ok := t.(Comparer)
fmt.Println(i, ok)
}
Run Code Online (Sandbox Code Playgroud)
和输出:
{1,'d'} {2,'b'} {3,'c'} {4,'a'} {4,'b'} {4,'c'}
{4 99} true
Run Code Online (Sandbox Code Playgroud)
因此,如果您准备使用已知类型(例如int
),请参阅此示例:
package main
import (
"container/list"
"fmt"
)
func Insert(val int, l *list.List) {
e := l.Front()
if e == nil {
l.PushFront(val)
return
}
for ; e != nil; e = e.Next() {
v := e.Value.(int)
if val < v {
l.InsertBefore(val, e)
return
}
}
l.PushBack(val)
}
func main() {
l := list.New()
Insert(4, l)
Insert(2, l)
Insert(3, l)
Insert(1, l)
for e := l.Front(); e != nil; e = e.Next() {
fmt.Print(e.Value, " ") // 1 2 3 4
}
fmt.Println()
}
Run Code Online (Sandbox Code Playgroud)
老的:
Go 中没有这样的接口。您可以编写此Less
函数来比较您的类型:
func Less(a, b interface{}) bool {
switch a.(type) {
case int:
if ai, ok := a.(int); ok {
if bi, ok := b.(int); ok {
return ai < bi
}
}
case string:
if ai, ok := a.(string); ok {
if bi, ok := b.(string); ok {
return ai < bi
}
}
// ...
default:
panic("Unknown")
}
return false
}
Run Code Online (Sandbox Code Playgroud)
测试示例代码:
package main
import (
"container/list"
"fmt"
)
func Less(a, b interface{}) bool {
switch a.(type) {
case int:
if ai, ok := a.(int); ok {
if bi, ok := b.(int); ok {
return ai < bi
}
}
case string:
if ai, ok := a.(string); ok {
if bi, ok := b.(string); ok {
return ai < bi
}
}
default:
panic("Unknown")
}
return false
}
func Insert(val interface{}, l *list.List) *list.Element {
e := l.Front()
if e == nil {
return l.PushFront(val)
}
for ; e != nil; e = e.Next() {
if Less(val, e.Value) {
return l.InsertBefore(val, e)
}
}
return l.PushBack(val)
}
func main() {
l := list.New()
Insert(4, l)
Insert(2, l)
Insert(3, l)
Insert(1, l)
for e := l.Front(); e != nil; e = e.Next() {
fmt.Print(e.Value, " ")
}
fmt.Println()
Insert("C", l)
Insert("A", l)
Insert("AB", l)
Insert("C", l)
Insert("C2", l)
Insert("C1", l)
for e := l.Front(); e != nil; e = e.Next() {
fmt.Print(e.Value, " ")
}
fmt.Println()
}
Run Code Online (Sandbox Code Playgroud)
输出:
1 2 3 4
1 2 3 4 A AB C C C1 C2
Run Code Online (Sandbox Code Playgroud)