2015-11-26 2 views
12

У меня есть этот пример кодаметод Golang с указателем приемника

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
} 

func (i Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() IFace { 
    obj := Implementation{someField: "Hello"} 
    return obj // <= Offending line 
} 

func main() { 
    a := Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 

SetSomeField не работает, как ожидалось, потому что его приемник не имеет тип указателя.

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

func (i *Implementation) SetSomeField(newValue string) { ... 

Компиляция это приводит к следующей ошибке:

prog.go:26: cannot use obj (type Implementation) as type IFace in return argument: 
Implementation does not implement IFace (GetSomeField method has pointer receiver) 

Как может У меня есть struct реализовать интерфейс и метод SetSomeField изменить значение фактического экземпляра без создания копии?

Вот фрагмент кода взломать: https://play.golang.org/p/ghW0mk0IuU

Я уже видел этот вопрос In go (golang), how can you cast an interface pointer into a struct pointer?, но я не могу понять, как это связано с этим примером.

+0

Оба метода требуют указатель приемников, иначе вы только реализуете часть интерфейса. – elithrar

ответ

16

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

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

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
}  

func (i *Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i *Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() *Implementation { 
    return &Implementation{someField: "Hello"} 
} 

func main() { 
    var a IFace 
    a = Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 
+0

Бах это было. Был другой метод, скрывающийся вокруг, который не был объявлен как приемник указателя. спасибо – Atmocreations

9

Простой ответ заключается в том, что у вас не будет возможности реализовать реализацию вашего интерфейса при работе SetSomeField так, как вы хотите.

Однако указатель на структуру будет реализовывать интерфейс, поэтому изменение метода Create для выполнения return &obj должно заставить все работать.

Основная проблема заключается в том, что ваш модифицированный метод SetSomeField больше не находится в методе Implementation. Хотя тип *Implementation наследует методы приемника без указателей, обратное неверно.

Причина этого связана с тем, как указаны интерфейсные переменные: единственный способ доступа к динамическому значению, хранящемуся в переменной интерфейса, - это его копирование. В качестве примера, представьте себе следующее:

var impl Implementation 
var iface IFace = &impl 

В этом случае, вызов iface.SetSomeField работ, поскольку он может скопировать указатель на использование в качестве приемника при вызове метода. Если мы непосредственно сохранили структуру в переменной интерфейса, нам нужно создать указатель на эту структуру для завершения вызова метода. После создания такого указателя можно (и потенциально модифицировать) динамическое значение переменной интерфейса без его копирования.

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