Должен ли я инкапсулировать срез и карты в Go?Если да, то как это сделать? - PullRequest
0 голосов
/ 28 мая 2019

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

Решение с геттерами прекрасно работает для всех типов данных, кроме срезов и карт, поскольку возвращаемые срезы и карты не копируются по умолчанию, поэтому их можно изменять. Единственное решение, которое мне удалось выяснить, - это создать новую карту / фрагмент и назначить все элементы в цикле, но это вводит много повторяющегося и уродливого кода, особенно для больших вложенных структур.

package main

import (
    "fmt"
)

type OtherStruct struct {
    prop string
}

type Struct struct {
    prop map[string]OtherStruct
}

func (s Struct) Prop() map[string]OtherStruct {
    return s.prop
}

func (s Struct) Prop2() map[string]*OtherStruct {
    prop := make(map[string]*OtherStruct, 0)
    for k := range s.prop {
        v := s.prop[k]
        prop[k] = &v
    }

    return prop
}

func main() {
    var s Struct;

    // Simple getter
    s = Struct{make(map[string]OtherStruct, 0)}
    p1 := s.Prop()
    fmt.Println(s) // &{map[]}
    p1["something"] = OtherStruct{"test"}
    fmt.Println(s) // {map[something:{test}]}

    // Getter which copies map
    s = Struct{make(map[string]OtherStruct, 0)}
    p2 := s.Prop2()
    fmt.Println(s) // &{map[]}
    p2["something"] = &OtherStruct{"test"}
    fmt.Println(s) // &{map[]}
}

Есть ли лучший способ инкапсулировать фрагменты / карты в Go? Или, может быть, я вообще не должен использовать инкапсуляцию в Go и использовать другой подход?

1 Ответ

1 голос
/ 28 мая 2019

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

В вашем примере пользователь Struct должен знать, что добавление новой записи в возвращенную карту будет отражаться для любого другого пользователята же карта

// Simple getter
s = Struct{make(map[string]OtherStruct, 0)}
p1 := s.Prop()
fmt.Println(s) // &{map[]}
p1["something"] = OtherStruct{"test"}
fmt.Println(s) // {map[something:{test}]}

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

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