Реализовать общий связанный список в golang, который запрещает разные типы в одном и том же связанном списке - PullRequest
0 голосов
/ 22 января 2019

Я хочу создать связанный список, который может содержать значения любого типа , но связанный список должен содержать значения любого только одного типа .

InВообще, когда я использую интерфейсы для достижения этой цели - любой тип, который реализует интерфейс для узла, может быть добавлен в связанный список.

Я написал реализацию для этого, где всякий раз, когда новый ключ добавляется в связанныйсписок, тип ключа проверяется по типу ключа в голове.Я хочу понять, является ли это правильным способом реализации или есть лучший способ сделать это.

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 голосов
/ 22 января 2019

Вы можете сделать это либо с помощью интерфейсов и проверок времени выполнения (как вы обнаружили), либо с помощью генерации кода . Это текущие параметры Go для общего программирования. Команда Go работает над тем, чтобы добавить дженерики к языку - это незавершенная работа, и каждый волен участвовать в обсуждении. Как только генерики появятся, они обеспечат решение, которое вы ищете здесь.

Что касается интерфейсов и генерации кода, то вы упомянули о производительности. Генерация кода будет генерировать более жесткий код, который не должен выполнять проверки во время выполнения для большинства операций; с другой стороны, это добавляет сложности в процесс сборки вашего проекта. Это обычный компромисс между разрешением чего-либо во время выполнения и предварительным вычислением во время компиляции.

...