Структуры с членами интерфейса и получателями указателей - PullRequest
0 голосов
/ 12 января 2020

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

Вот как я Я определяю мое двоичное дерево.

type btree interface {
    display(io.Writer)
    add(int) btree
    replace(int, int)//A test to see if we are sharing nodes
}

узлы двоичного дерева определяются следующим образом:

type node struct {
    data  int
    left  btree
    right btree
}

и пустой узел двоичного дерева

type empty struct{}

Функция и методы

func createEmpty() btree {
    return &empty{}
}

Методы для структуры узлов

//replace is just a test to see if I'm sharing nodes
func (n *node) replace(value, replacement int) {
    if n.data < value {
        n.left.replace(value, replacement)
    } else if n.data > value {
        n.right.replace(value, replacement)
    } else {
        n.data = replacement
    }
}

func (n *node) add(data int) btree {
    if n.data < data {
        l := &node{n.data, n.left.add(data), n.right}
        return l
    } else if n.data > data {
        r := &node{n.data, n.left, n.right.add(data)}
        return r
    } else {
        return n
    }
}

func (n *node) display(w io.Writer) {
    n.left.display(w)
    fmt.Fprintln(w, n.data)
    n.right.display(w)
}

Методы для пустых узлов

//replace is just a test to see if I'm sharing nodes
func (*empty) replace(_, _ int) {}

func (e *empty) add(data int) btree {
    en := &node{data, e, e}
    return en
}

func (*empty) display(w io.Writer) {
    fmt.Fprintln(w, "Empty")
}

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

Вот рабочая копия кода ниже:

package main

import (
    "fmt"
    "io"
    "os"
)

func createEmpty() btree {
    return &empty{}
}

type btree interface {
    display(io.Writer)
    add(int) btree
    replace(int, int)
}

type node struct {
    data  int
    left  btree
    right btree
}

func (n *node) replace(value, replacement int) {
    if n.data < value {
        n.left.replace(value, replacement)
    } else if n.data > value {
        n.right.replace(value, replacement)
    } else {
        n.data = replacement
    }
}

func (n *node) add(data int) btree {
    if n.data < data {
        l := &node{n.data, n.left.add(data), n.right}
        return l
    } else if n.data > data {
        r := &node{n.data, n.left, n.right.add(data)}
        return r
    } else {
        return n
    }
}

func (n *node) display(w io.Writer) {
    n.left.display(w)
    fmt.Fprintln(w, n.data)
    n.right.display(w)
}

type empty struct{}

func (*empty) replace(_, _ int) {}

func (e *empty) add(data int) btree {
    en := &node{data, e, e}
    return en
}

func (*empty) display(w io.Writer) {
    fmt.Fprintln(w, "Empty")
}

func main() {
    bt := createEmpty().add(5).add(1).add(8).add(2)
    bt2 := bt.add(7).add(6).add(10).add(9)
    bt.display(os.Stdout)
    fmt.Fprintln(os.Stdout, "\n--->")
    bt2.display(os.Stdout)
    fmt.Fprintln(os.Stdout, "\n\n--->")
    //The node with 1 should be shared with bt and bt2
    //so if we change bt's node 1 to 4143
    //we should see the change in bt2 too   
    bt.replace(1, 4143)
    bt.display(os.Stdout)//We see the change here, 1 is now 4143
    fmt.Fprintln(os.Stdout, "\n--->")
    bt2.display(os.Stdout)//We see the change here, 1 is now 4143
}

1 Ответ

1 голос
/ 12 января 2020

Учитывая эту структуру:

type node struct {
    data  int
    left  btree
    right btree
}

и функцию f с приемником указателя q:

func (n *node) f() {}

f получает указатель на node. Любые изменения f, внесенные в узел n, будут отражены в копии, которая используется для вызова f.

Точнее, при вызове n.f() и если n *node, затем копия этого указателя отправляется на f, который все еще указывает на тот же объект, что и n. Если n не является указателем, то &n будет отправлено на f.

Чтобы ваш код работал, левый и правый btree интерфейсы также должны связываться с *node с, а не с node с (вы уже сделали это правильно). Это потому, что если вы, например, вызываете node.left.replace, вы хотите заменить значение в node.left. Если у вас был получатель значения для функции replace, то при вызове node.left.replace копия этого левого узла будет отправлена ​​в функцию replace в качестве получателя, а изменения не будут видны в node.left узел.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...