уже делает (другую) копию, так что самое большее вы можете изменить только копию копии. Смотрите отредактированный ответ.

ли изменить тип указателя и значение переменной, определенной интерфейсом?

Я могу изменить значение указателя с помощью отражения:v.Elem().Set(reflect.ValueOf(&Greeter{"Jack"}).Elem()) что эквивалентноa = &Greeter{"Jack"}.

Но как я могу сделать отражение эквивалентным дляa = &Greeter2{"Jack"}?

ОБНОВЛЕНИЕ: К сожалению в реальной проблеме, которую я пытаюсь решить, я не могу обратиться к исходной переменной (panic: reflect: reflect.Value.Set using unaddressable value), поэтому я пытаюсь обойти на уровне указателя.

Вот полный пример кода:

package main

import (
    "fmt"
    "reflect"
)

type Greeter struct {
    Name string
}

func (g *Greeter) String() string {
    return "Hello, My name is " + g.Name
}

type Greeter2 struct {
    Name string
}

func (g *Greeter2) String() string {
    return "Hello, My name is " + g.Name
}

func main() {
    var a fmt.Stringer
    a = &Greeter{"John"}

    v := reflect.ValueOf(a)
    v.Elem().Set(reflect.ValueOf(&Greeter{"Jack"}).Elem())
    //v.Elem().Set(reflect.ValueOf(&Greeter2{"Jack"}).Elem()) // panic: reflect.Set: value of type main.Greeter2 is not assignable to type main.Greeter
    fmt.Println(a.String()) // Hello, My name is Jack

    a = &Greeter2{"Ron"}
    fmt.Println(a.String()) // Hello, My name is Ron
}

Ответы на вопрос(1)

Решение Вопроса

начение типа интерфейса, будет сделана копия значения интерфейса (вместе с(value;type) внутри), и вы сможете изменить только копию, которая не повлияет на оригинал.

У вас есть переменнаяa типа интерфейса. Если вы хотите изменить значение, хранящееся в этой переменной, вы должны передать / использовать адрес этой переменной.

Сначала давайте изменимGreeter2.String() метод, чтобы узнать, какой из них вызывается:

func (g *Greeter2) String() string {
    return "Hello2, My name is " + g.Name
}

А также позвонитьa.String() после первого init, чтобы увидеть, что он изначально содержит*Greeter ценность, поскольку мы скоро изменим это.

var a fmt.Stringer
a = &Greeter{"John"}
fmt.Println(a.String()) // Hello, My name is John

v := reflect.ValueOf(&a).Elem()
v.Set(reflect.ValueOf(&Greeter2{"Jack"}))
fmt.Println(a.String()) // Hello2, My name is Jack

a = &Greeter2{"Ron"}
fmt.Println(a.String()) // Hello2, My name is Ron

Вывод (попробуйте наGo Playground):

Hello, My name is John
Hello2, My name is Jack
Hello2, My name is Ron

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

Итак, ключевые вещи были:

Начните с адреса:reflect.ValueOf(&a)И вы должны установить значение указателя в него как только*Greeter2 инвентарьfmt.String, но нетGreeter, ВидетьGo, X не реализует Y (... у метода есть указатель получателя) для деталей.

Для получения более подробной информации и углубленного ознакомления читайте:The Go Blog: Законы Отражения

Редактировать: об изменении копии

Первый раздел моего ответа: всякий раз, когда вы передаете что-либо, копия делается. Это также включает передачу значения интерфейсаreflect.ValueOf(): это также получит копию, так что вы не можете избежать этого. Единственный способ сделать эту работу - пройтиуказатель; потому что указатель также будет скопирован, но мы модифицируемзаостренный значение (не указатель), которое одинаково.

 vearutop21 сент. 2017 г., 13:35
К сожалению, я пропустил существенную вещь в своем вопросе, мне нужен трюк отражения, чтобы повлиять на копииa, Я пытаюсь исправитьgithub.com/boolean64/inject/blob/master/inject_test.go#L227 работать сGreeter2, В этом случае исходная переменная не устанавливаетсяpanic: reflect: reflect.Value.Set using unaddressable value.
 icza21 сент. 2017 г., 13:41
@vearutop Невозможно позвонитьreflect.ValueOf() уже делает (другую) копию, так что самое большее вы можете изменить только копию копии. Смотрите отредактированный ответ.

Ваш ответ на вопрос