2016-06-30 3 views
4

У меня есть следующий:Golang Метод Override

type Base struct { 

} 

func(base *Base) Get() string { 
    return "base" 
} 

func(base *Base) GetName() string { 
    return base.Get() 
} 

Я хочу, чтобы определить новый тип с новой реализацией Get(), так что я могу использовать новый тип вместо Base и где GetName() называется его вызовом новой реализации Get(). Если бы я использовал Java, я бы наследовал Base и переопределял Get(). Как я должен достичь этого в Go? Я хочу, если это возможно, не нарушать какие-либо изменения, поэтому существующие потребители базы не нуждаются в изменении.

Мой первый удар в это похоже ..

type Sub struct { 
    Base 
} 

func(sub *Sub) Get() string { 
    return "Sub" 
} 

..which не работает. Мой мозг не связан с Go, но ясно.

+2

Возможный дубликат [ возможно ли вызывать переопределенный метод из родительской структуры в golang?] (http: // stacko verflow.com/questions/21251242/is-it-possible-to-call-overridden-method-from-parent-struct-in-golang) – Vadyus

+1

Go не имеет наследования и не имеет дженериков. Если что-то ожидает тип 'Base', вы не можете предоставить его другим типом. – JimB

ответ

2

Go не является «классическим» языком OO: он не знает концепции классов и наследования.

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

Интерфейс определяет набор методов, но эти методы не содержат кода: они не реализованы (это означает, что они абстрактны).

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

Вот простой пример, чтобы доказать это:

package main 

import (
    "fmt" 
) 

type Base struct{} 
type Baser interface { 
    Get() float32 
} 

type TypeOne struct { 
    value float32 
    Base 
} 

type TypeTwo struct { 
    value float32 
    Base 
} 

type TypeThree struct { 
    value float32 
    Base 
} 

func (t *TypeOne) Get() float32 { 
    return t.value 
} 

func (t *TypeTwo) Get() float32 { 
    return t.value * t.value 
} 

func (t *TypeThree) Get() float32 { 
    return t.value + t.value 
} 

func main() { 
    base := Base{} 
    t1 := &TypeOne{1, base} 
    t2 := &TypeTwo{2, base} 
    t3 := &TypeThree{4, base} 

    bases := []Baser{Baser(t1), Baser(t2), Baser(t3)} 

    for s, _ := range bases { 
     switch bases[s].(type) { 
     case *TypeOne: 
      fmt.Println("TypeOne") 
     case *TypeTwo: 
      fmt.Println("TypeTwo") 
     case *TypeThree: 
      fmt.Println("TypeThree") 
     } 

     fmt.Printf("The value is: %f\n", bases[s].Get()) 
    } 
} 

Go Playground

+5

Я не думаю, что это отвечает на вопрос. Он хотел создать экземпляр подкласса, вызвать GetName и на самом деле вызвать метод подкласса. Этот пример не делает попыток решить эту проблему. –

1

Интерфейсы названы коллекции сигнатур методов:
см: https://gobyexample.com/interfaces
и: http://www.golangbootcamp.com/book/interfaces
, так что лучше не использовать в таком способе ООП.


, что вы спрашиваете не Golang идиоматические но возможных (2 пути):

это то, что вам нужно (рабочий пример кода):

package main 

import "fmt" 

type Base struct { 
} 

func (base *Base) Get() string { 
    return "base" 
} 

type Getter interface { 
    Get() string 
} 

func (base *Base) GetName(getter Getter) string { 
    if g, ok := getter.(Getter); ok { 
     return g.Get() 
    } else { 
     return base.Get() 
    } 
} 

// user code : 
type Sub struct { 
    Base 
} 

func (t *Sub) Get() string { 
    return "Sub" 
} 
func (t *Sub) GetName() string { 
    return t.Base.GetName(t) 
} 

func main() { 
    userType := Sub{} 
    fmt.Println(userType.GetName()) // user string 
} 

выход:

как вы видите, код инициализации должен быть выполнен в коде пользователя:

func (t *Sub) GetName() string { 
    return t.Base.GetName(t) 
} 

также это работает:

package main 

import "fmt" 

type Getter interface { 
    Get() string 
} 

type Base struct { 
    Getter 
} 

func (base *Base) Get() string { 
    return "base" 
} 

func (base *Base) GetName() string { 
    return base.Getter.Get() 
} 

// user code : 
type Sub struct { 
    Base 
} 

func (t *Sub) Get() string { 
    return "Sub" 
} 
func New() *Sub { 
    userType := &Sub{} 
    userType.Getter = interface{}(userType).(Getter) 
    return userType 
} 

func main() { 
    userType := New() 
    fmt.Println(userType.GetName()) // user string 
} 

выход:

как вы видите один код инициализации должно быть сделано в коде пользователя:

userType.Getter = interface{}(userType).(Getter)