Смущает эти фрагменты кода реализации интерфейса и вызова? - PullRequest
0 голосов
/ 11 октября 2018

Версия Go

  • версия Go go1.11 darwin / amd64

Код 1:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

//func GotU(t esc);
func (e esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(test)

    fmt.Println(test.i)

}

Код 2:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

func (e esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(&test)

    fmt.Println(test.i)

}

Код 3:

package main

import "fmt"

type myintf interface {
    GotU()
}

type esc struct {
     i int
}

func (e *esc)GotU() {
    e.i = 10
}

func TestFunc(it myintf) string {
    it.GotU()
    return  "kk"
}

func main() {

    var test esc
    test.i = 9

    TestFunc(test)

    fmt.Println(test.i)

}

Выходы:

  • Вывод кода 1: 9
  • Вывод кода 2: 9
  • код 3 не может быть скомпилирован из-за несоответствия типов

Поскольку реализован только func (e esc)GotU(), почему оба куска кода должны работать и давать одинаковый результат?Для меня довольно странно передавать указатель структуры этой функции (TestFunc), чтобы получить тот же ответ.

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Разница между 1-й и второй версией заключается в том, что вы передаете структуру непосредственно в одной версии, а указатель на структуру - в другой версии.В этом случае эти программы работают одинаково, так как указатель также включает все определенные функции в структуре.

Но это не работает наоборот.Вы определяете метод GotU на приемнике указателя.Структура не знает об этой функции.Если вы вызовете

TestFunc(&test)

в третьей программе, он скомпилируется, но будет работать не так, как две другие: Вывод: "10"

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

0 голосов
/ 11 октября 2018

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

func (e *esc) GotU() {
    e.i = 10
}

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

type myintf interface {
    GotU()
}

Поэтому вам нужно передать адрес структуры в TestFunc.Это причина того, что вы получаете ошибку несоответствия типов, потому что вы передаете переменную типа esc, в то время как вашему методу требуется переменная *esc.

func main() {

    var test esc
    test.i = 9
    TestFunc(&test)
    fmt.Println(test.i)

}

Пример работы на Go Play *

В Golang есть два способа передать приемник метода.

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value

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

Во-первых, и самое главное, должен ли метод модифицировать приемник?Если это так, получатель должен быть указателем.(Срезы и карты действуют как ссылки, поэтому их история немного более тонкая, но, например, чтобы изменить длину среза в методе, получатель должен оставаться указателем.) В приведенных выше примерах, если pointerMethod изменяет поляs, вызывающая сторона увидит эти изменения, но valueMethod вызывается с копией аргумента вызывающей стороны (это определение передачи значения), поэтому сделанные изменения будут невидимы для вызывающей стороны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...