Eu queria expandir a resposta dada por @jimt aqui . Essa resposta está correta e me ajudou tremendamente a resolver isso. No entanto, existem algumas ressalvas nos dois métodos (alias, incorporar) com os quais tive problemas.
nota : eu uso os termos pai e filho, embora não tenha certeza de que seja o melhor para composição. Basicamente, pai é o tipo que você deseja modificar localmente. Filho é o novo tipo que tenta implementar essa modificação.
Método 1 - Definição de tipo
type child parent
// or
type MyThing imported.Thing
- Fornece acesso aos campos.
- Não fornece acesso aos métodos.
type child struct {
parent
}
// or with import and pointer
type MyThing struct {
*imported.Thing
}
- Fornece acesso aos campos.
- Fornece acesso aos métodos.
- Requer consideração para inicialização.
Resumo
- Usando o método de composição, o pai incorporado não será inicializado se for um ponteiro. O pai deve ser inicializado separadamente.
- Se o pai incorporado for um ponteiro e não for inicializado quando o filho for inicializado, ocorrerá um erro de desreferência de ponteiro nulo.
- Os casos de definição de tipo e incorporação fornecem acesso aos campos do pai.
- A definição de tipo não permite acesso aos métodos do pai, mas a incorporação do pai o faz.
Você pode ver isso no código a seguir.
exemplo de trabalho no parquinho
package main
import (
"fmt"
)
type parent struct {
attr string
}
type childAlias parent
type childObjParent struct {
parent
}
type childPointerParent struct {
*parent
}
func (p *parent) parentDo(s string) { fmt.Println(s) }
func (c *childAlias) childAliasDo(s string) { fmt.Println(s) }
func (c *childObjParent) childObjParentDo(s string) { fmt.Println(s) }
func (c *childPointerParent) childPointerParentDo(s string) { fmt.Println(s) }
func main() {
p := &parent{"pAttr"}
c1 := &childAlias{"cAliasAttr"}
c2 := &childObjParent{}
// When the parent is a pointer it must be initialized.
// Otherwise, we get a nil pointer error when trying to set the attr.
c3 := &childPointerParent{}
c4 := &childPointerParent{&parent{}}
c2.attr = "cObjParentAttr"
// c3.attr = "cPointerParentAttr" // NOGO nil pointer dereference
c4.attr = "cPointerParentAttr"
// CAN do because we inherit parent's fields
fmt.Println(p.attr)
fmt.Println(c1.attr)
fmt.Println(c2.attr)
fmt.Println(c4.attr)
p.parentDo("called parentDo on parent")
c1.childAliasDo("called childAliasDo on ChildAlias")
c2.childObjParentDo("called childObjParentDo on ChildObjParent")
c3.childPointerParentDo("called childPointerParentDo on ChildPointerParent")
c4.childPointerParentDo("called childPointerParentDo on ChildPointerParent")
// CANNOT do because we don't inherit parent's methods
// c1.parentDo("called parentDo on childAlias") // NOGO c1.parentDo undefined
// CAN do because we inherit the parent's methods
c2.parentDo("called parentDo on childObjParent")
c3.parentDo("called parentDo on childPointerParent")
c4.parentDo("called parentDo on childPointerParent")
}
“extension methods are not object-oriented”
) para C #, mas, ao analisá-los hoje, fui imediatamente lembrado das interfaces do Go (e sua abordagem para repensar a orientação a objetos), e então tive essa pergunta.