Slice vs type alias в качестве приемника метода - PullRequest
1 голос
/ 20 февраля 2020

У меня есть структура Foo с методом print:

type Foo struct {
    Bar string
}
func (f Foo) print() {
    fmt.Println(f.Bar)
}

Если я хочу напечатать для фрагмента Foo, возможно, каноническим способом будет написать for l oop, и есть функция для его инкапсуляции:

func printFoos(fs []Foo) {
    for _, f := range fs {
        f.print()
    }
}
printFoos([]Foo{})

Исходя из OOP фона, я нахожу этот подход немного непривлекательным.

Что я хотел бы сделать должен связать printFoos с []Foo:

// Invalid Go code
func (fs []Foo) print() {
    for _, f := range fs {
        f.print()
    }
}

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

Чтобы обойти это, можно написать:

type Foos []Foo
func (fs Foos) print() {
    for _, f := range fs {
        f.print()
    }
}

Чтобы использовать его, я должен явно объявить тип как Foos, поэтому я не могу использовать print на []Foo

fs := []Foo{}
fs.print() // error
var fss Foos = fs
fss.print()

Что меня смущает, так это то, что в приведенном выше коде fss и fs явно одного и того же типа, как я могу назначить fs на fss без ошибок. Однако мы не можем просто использовать fs.print() и позволить Go быть умными в отношении преобразования.

Почему это так?

Полный код может можно найти на детской площадке .

1 Ответ

6 голосов
/ 20 февраля 2020

Что меня смущает, так это то, что в приведенном выше коде fss и fs явно одного и того же типа, поскольку я могу присвоить fs fss без ошибок.

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

fss имеет тип Foos, а fs имеет тип []Foo, безымянный тип среза. Это правда, что они имеют один и тот же базовый тип, поэтому вы можете назначить fs на fss, как указано в этом правиле присваивания:

Значение x равно назначаемому к переменной типа Tx назначается на T»), если применяется одно из следующих условий:

Методы привязаны к конкретным типам. Таким образом, метод Foos.print() недоступен для значения другого типа, включая []Foo.

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

Foos(fs).print()

Это преобразование не меняет структуру памяти, а только ее тип, поэтому она безопасна и эффективна. Мы использовали его только для получения доступа к методу типа с идентичным базовым типом.

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