Определение типа: указатель против значения - PullRequest
0 голосов
/ 18 февраля 2020

Я новичок в Go и хотел бы продлить treemap.Map из GoDS проекта.

Я начал с определения псевдонима типа для treemap.Map:

import "github.com/emirpasic/gods/maps/treemap"

type Index = treemap.Map

func (idx Index) Add(k int, v int) {
    idx.Put(k, v)
}

Получение следующей ошибки компиляции: cannot define new methods on non-local type treemap.Map

После этого я изменил псевдоним типа к определению типа:

type IndexType treemap.Map 

func (idx IndexType) Add(k int, v int) {
    idx.Put(k, v)
}

Теперь я начал получать следующую ошибку: idx.Put undefined (type IndexType has no field or method Put).

Первоначально предполагалось, что я получаю эту ошибку, потому что Put определен для типа указателя и на основании этого наивного предположения я изменил тип получателя:

func (idx *IndexType) Add(k int, v int) {
    idx.Put(k, v)
}

Doesn ' t compile: idx.Put undefined (type *IndexType has no field or method Put)

Попробовал другой способ:

func (idx IndexType) Add(k int, v int) {
    (&idx).Put(k, v)
}

Не компилируется: (&idx).Put undefined (type *IndexType has no field or method Put)

Я также пытался type IndexType *treemap.Map, но это не удалось приведи меня ко всему. Я потратил несколько часов, пытаясь понять логику c, стоящую за этими ошибками, но не смог найти логического объяснения.

Я знаю, что могу достичь своей цели, используя embedding:

import "github.com/emirpasic/gods/maps/treemap"

type IndexType struct {
    *treemap.Map
}

func (idx IndexType) Add(k int, v int) {
    idx.Put(k, v)
}

Приведенный выше код компилируется.

Однако у меня остается вопрос: можно ли расширить тип, например treemap.Map, используя оператор type? голе

1 Ответ

1 голос
/ 19 февраля 2020

Возможно, это слишком явно указано в Go spe c:

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

Это означает, что при определении типа, подобного type Foo Bar, где Foo и Bar оба именованных типа, базовый тип из Foo равен , а не Bar. Это Bar базовый тип . Если Bar является struct, то базовым типом Foo является struct literal , который определяет Bar (или тип Bar основан на и т. Д.). Поскольку у литерала структуры нет методов, нет и Foo; методы, определенные в Bar, определены только в Bar, а не в литерале структуры, который может быть его базовым типом. Так что Foo не имеет методов.

Foo также не имеет "родительского типа"; он имеет только его базовый тип, который является литералом структуры. Здесь нет иерархии типов; вы можете type Foo Bar, затем type Baz Foo, затем type Qux Baz, и ни у одного из них нет «знания» друг о друге; все они просто разделяют базовый тип, который является просто макетом памяти для хранения данных типа.

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