2016-10-25 5 views
5

Так у меня есть этот пример здесь: Go PlaygroundGolang: Тип назначение с другой структурой

package main 

import (
    "fmt" 
) 

type Circle struct{} 

func (c Circle) Something() { 
    fmt.Println("something") 
} 

type Rectangle struct { 
    Circle 
} 

func (a Rectangle) SomethingElse() { 
    fmt.Println("SomethingElse") 
} 

type Form Rectangle 

func main() { 
    c := Form{} 
    c.Circle.Something() 
    c.SomethingElse() 
} 

Я не понимаю, почему я могу назвать Something от встроенного Circle, но не может назвать Somethingelse из Rectangle в пределах Form type. Также я не понимаю, какую пользу я получу, когда объявляю тип какого-либо другого типа, например, здесь, в Form.

ответ

8

Это:

type Form Rectangle 

Создает тип нового с именем Form, имеющим Rectangle в качестве своего типа , лежащие в основе.

Это означает, что поля Rectangle (который является структурой) будут определены для Form.

Но методы привязаны к определенному типу. Когда вы создаете новый тип (Form), этот новый тип не будет иметь каких-либо методов его базового типа, поэтому вы не можете позвонить c.SomethingElse(), так как SomethingElse() - это метод типа Rectangle.

c.Circle.Something() работы, потому что c.Circle является полем типа Circle и Something() представляет собой метод Circle типа.

Если вы хотите позвонить по методу Rectangle.SomethingElse(), для которого требуется значение типа Rectangle (тип приемника: Rectangle). Поскольку основной тип Form является Rectangle, вы можете просто получить значение типа Rectangle из значения типа Form с помощью простого типа conversion:

Rectangle(c).SomethingElse() // This works 

Преимущества создания нового типа является то, что таким образом Вы можете создать/добавьте свои собственные методы. Общим примером является использование интерфейса sort.Interface. Допустим, у вас есть кусочек чего-то, например. []Rectangle или фрагмент некоторого типа, который у вас нет контроля (потому что он является частью другого пакета), а методы для типа могут быть определены только в одном пакете). Если вы хотите отсортировать этот кусок, вы создаете новый тип, для которого можно определить методы, методы sort.Interface и т.д .:

type SortRectangle []Rectangle 

func (s SortRectangle) Len() int   { return len(s) } 
func (s SortRectangle) Less(i, j int) bool { return s[i] <some-logic> s[j] } 
func (s SortRectangle) Swap(i, j int)  { s[i], s[j] = s[j], s[i] } 

sort.Sort() функция может сортировать любые значения, которые реализуют sort.Interface. []Rectangle нет, но мы только что создали новый тип SortRectangle, который делает.И если у нас есть значение типа []Rectangle, мы можем преобразовать его в SortRectangle, потому что первый является базовым типом последнего, и, выполнив преобразование, мы имеем значение типа SortRectangle, которое может быть передано sort.Sort(), чтобы есть она сортируется:

rs := []Rectangle{} 
// Sort rs: 
sort.Sort(SortRectangle(rs)) 

Обратите внимание, что преобразование, как выше SortRectangle(rs) только изменяет информацию о типе времени выполнения, это не меняет представление памяти rs, так что pefectly безопасно и эффективного.

Если вы хотите, чтобы новый тип имел методы «старого» типа, тогда используйте вложение. См. Ответ Айнара-Г. На самом деле, вы уже сделали это, встраивая Circle в Rectangle: тип Rectangle имеет метод Something(), потому что Something() является метод Circle:

Rectangle{}.Something() // Prints "something" 
+0

Thx для отличного объяснения! – simplebird

1

Все (и только) причина сделать type Form Rectangle является определение новый тип с разные методы. В вашем примере: никаких методов. c - Форма и не имеет методов, это только raison d'être не с SomethingElse() метод.

Но Form все еще вкладывается круг, который доступен в качестве c.Circle и который является Circle так obviousely имеет метод Something().

3

Простой правило в Go. Если вы хотите, методы типа, делает

type A struct { B } 

и если вы не хотят методы типа, делает

type A B 

Зачем нам нужен второй вид? Интерфейсы, например. Иногда мы не делаем хотим, чтобы значение удовлетворяло интерфейсу, например here. В других случаях вам просто нужны типы, а не их методы.

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

Смежные вопросы