在golang中实现通用链表,这不允许同一链表中的不同类型

时间:2019-01-22 04:42:29

标签: go data-structures linked-list

我想创建一个链表,该链表可以容纳任何类型的,但是链表必须仅容纳任何一种类型的值

通常,当我使用接口来实现此目的时,可以将实现节点接口的任何类型添加到链接列表中。

我为此编写了一个实现,其中,每当将一个新的密钥添加到链接列表中时,就会对照头部的密钥类型来检查密钥的类型。我想了解这是否是实现它的正确方法,还是有更好的实现方法。

package main

import (
    "errors"
    "fmt"
    "reflect"
    "strings"
)

type MyNode struct {
    value int
}

func (node *MyNode) PrintValue() {
    fmt.Printf(" %d ", node.value)
}

type llNode struct {
    key        llNodeInterface
    next       *llNode
    llNodeType reflect.Type
}

type llNodeInterface interface {
    PrintValue()
}

type ComplexNode struct {
    realValue  int
    imageValue int
}

func (node *ComplexNode) PrintValue() {
    fmt.Printf(" %d + i%d", node.realValue, node.imageValue)
}

// Student type.
type Student struct {
    name string
    age  int
}

// Student implements the PrintValue function - thus llNodeInterface is implemented.
func (node *Student) PrintValue() {
    fmt.Printf("Name: %s | Age : %d ", node.name, node.age)
}

// Function which will check the of the new node before adding to the linked
// list. It checks the type of the new key against the type of the key in the
// head. If both are equal then it proceed else return error.
func (head *llNode) AddBeforeHeadTypeCheck(passedKey llNodeInterface) error {

    if head.key == nil {
        head.key = passedKey
        head.llNodeType = reflect.TypeOf(head.key)
    } else {
        typeOfPassedKey := reflect.TypeOf(passedKey)

        if typeOfPassedKey != head.llNodeType {
            fmt.Printf("\nUnsupported type for the type %T", passedKey)
            return errors.New("Type mistmatch")
        }

        temp := llNode{key: head.key, next: head.next}
        head.key = passedKey
        head.next = &temp
    }
    return nil
}

// Function which will not check the types and will simply add the new node to
// the linked list. Thus linked list will be able to have nodes of multiple
// types.
func (head *llNode) AddBeforeHead(passedKey llNodeInterface) {

    if head.key == nil {
        head.key = passedKey
        head.llNodeType = reflect.TypeOf(head.key)
    } else {
        temp := llNode{key: head.key, next: head.next}
        head.key = passedKey
        head.next = &temp
    }
}

func (head *llNode) Init() {
    head.key = nil
    head.next = nil
    head.llNodeType = nil

}

// Print the linked list.
func (head *llNode) DisplayLL() {

    temp := head
    fmt.Printf("\n%s", strings.Repeat("#", 80))
    fmt.Printf("\nPrinting the linked list\n")

    for {
        if temp.key == nil {
            fmt.Println("Linked list is empty")
            break
        } else {
            fmt.Printf("\n %T %v ", temp.key, temp.key)
            key := temp.key
            key.PrintValue()
            if temp.next == nil {
                break
            } else {
                temp = temp.next
            }
        }
    }
    fmt.Printf("\n%s", strings.Repeat("#", 80))
    fmt.Printf("\n\n")
}

func testWithMixedType() {
    head := llNode{}
    head.Init()

    for i := 1; i < 10; i++ {
        temp := &ComplexNode{i, i * 10}
        head.AddBeforeHeadTypeCheck(temp)
    }

    temps := &Student{"rishi", 20}
    head.AddBeforeHeadTypeCheck(temps) // Will give error.
    head.DisplayLL()
}

func testWithComplexNumber() {

    head := llNode{}
    head.Init()

    for i := 1; i < 10; i++ {
        temp := &ComplexNode{i, i * 10}
        head.AddBeforeHeadTypeCheck(temp)
    }

}

func main() {
    testWithComplexNumber()
    testWithMixedType()

}

代码运行正常-但我想了解是否有更好或不同的方式来实现此目的。

还-当前使用反射包检查类型对性能有何影响?实现同一件事是否有另一种方式。

* main.Student类型的不受支持的类型

Unsupported type for the type *main.Student
################################################################################
Printing the linked list

 *main.ComplexNode &{9 90}  9 + i90
 *main.ComplexNode &{8 80}  8 + i80
 *main.ComplexNode &{7 70}  7 + i70
 *main.ComplexNode &{6 60}  6 + i60
 *main.ComplexNode &{5 50}  5 + i50
 *main.ComplexNode &{4 40}  4 + i40
 *main.ComplexNode &{3 30}  3 + i30
 *main.ComplexNode &{2 20}  2 + i20
 *main.ComplexNode &{1 10}  1 + i10
################################################################################

1 个答案:

答案 0 :(得分:1)

您可以通过使用接口和运行时检查(如您所发现的)或通过使用code generation来做到这一点。这些是Go中用于通用编程的当前选项。 Go小组正在努力add generics to the language-这项工作仍在进行中,每个人都可以自由参加讨论。泛型一旦存在,它们将提供您在此处寻求的解决方案。

对于接口与代码生成,您提到了性能。代码生成将生成更紧密的代码,无需对大多数操作进行运行时检查。另一方面,它增加了项目构建过程的复杂性。这些是通常的权衡取舍,即在运行时解决某些问题与在编译时进行预计算。