2015-09-01 2 views
1

Мой вариант использования: мне нужно иметь несколько структур в Go, у кого будут методы с теми же сигнатурами и необязательно должны иметь все методы. Следующий код описывает требования, а также представляет мое текущее решение.Prototyping struct в Go

type calc struct { 
    fn func(a, b int) int 
    gn func(a string) bool 
    name string 
} 

func add(a, b int) int { 
    return a + b 
} 

func bar(foo string) bool { 
    // do something 
} 

func sub(a, b int) int { 
    return a - b 
} 

func main() { 
    for c := range []calc{{ 
     fn: add, 
     gn: bar, 
     name: "addition", 
    }, { 
     fn: sub, 
     name: "subtraction", 
    }} { 
     fmt.Printf("%s(10, 15) returned: %d\n", c.name, c.fn(10, 15)) 
     if c.gn != nil { 
      c.gn(c.name) 
     } 
    } 
} 

Мой вопрос в том, как улучшить этот код? Каков наилучший способ достичь этого в Go? Могу ли я получить лучшее решение с использованием интерфейса?

+0

Что такое 'c.foo' и откуда берется' gn' (функция, а не метод)? –

+0

@ Ainar-G Ах, извините, обновлено – Fallen

ответ

4

Использование интерфейсов.

type Op interface { 
    Name() string 
    Do(a, b int) int 
} 

type Add struct{} 

func (Add) Name() string { return "add" } 
func (Add) Do(a, b int) int { return a + b } 

type Sub struct{} 

func (Sub) Name() string { return "sub" } 
func (Sub) Do(a, b int) int { return a - b } 

Детская площадка: http://play.golang.org/p/LjJt6D0hNF.


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

type RevOp interface { 
    Op 
    ReverseDo(a, b int) int 
} 

// ... 

func (Add) ReverseDo(a, b int) int { return a - b } 

// ... 

fmt.Printf("%s(10, 15) returned: %d\n", op.Name(), op.Do(10, 15)) 
if op, ok := op.(RevOp); ok { 
    fmt.Printf("reverse of %s(10, 15) returned: %d\n", op.Name(), op.ReverseDo(10, 15)) 
} 

площадка: http://play.golang.org/p/MQ6LlPDcEi.

+0

Я знаю это решение, но я смущен, если это улучшает его. Мне это не нравится, так как нам нужно иметь дополнительную функцию для установки/получения значений полей struct. Есть ли какая-то определенная логика go-pher, для которой эта версия лучше, чем мой фиктивный код? – Fallen

+0

@Fallen без конкретного примера того, что у вас есть * и *, что бы вы хотели, я не думаю, что вы можете получить лучшее решение. Ваш фиктивный пример кажется идеальным вариантом использования интерфейсов. –

+0

Я думаю, что основное функциональное различие между ними состоит в том, что если у вас есть переменная, содержащая функцию (код op), переменная может быть «nil» и невосстанавливаема, но если вы пытаетесь создать структуру, которая будет использовать интерфейс, то либо структура будет иметь функцию, либо она не будет соответствовать интерфейсу (т. е. если он соответствует интерфейсу, то вы знаете, что функция должна быть определена и вызвана) –

0

Я обсуждал с некоторыми людьми лично и, по-видимому, мое решение было правильным. Хотя его можно переписать с помощью интерфейса, это не обязательно является улучшением.

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