Внутреннее состояние встроенных типов в golang - как это работает? - PullRequest
0 голосов
/ 10 марта 2020

Я пытаюсь обернуть голову вокруг встраивания в golang, и я немного растерялся, когда дело доходит до состояния типа, встроенного в другой.

Вот мой вопрос: если я иметь тип Embedii, который является целым числом, и у него есть метод, который влияет на его значение, должно ли оно появляться в типе, который его встраивает?

Вот что я играл:

package main

import (
  "fmt"
)

type Embedii int

func (y *Embedii) Do() {
  if y == nil {
    y = new(Embedii)
  } else {
    *y = *y + 1
  }
  fmt.Println(*y)
}

type Embedder struct {
  *Embedii
}

func main() {
  embedii := new(Embedii)
  embedii.Do() // prints 1
  embedii.Do() // prints 2

  fmt.Println("---")

  embedder := new(Embedder)
  embedder.Do() // prints 0
  embedder.Do() // prints 0

  fmt.Println("---")

  nembedii := new(Embedii)
  embedo := &Embedder{nembedii}
  embedo.Do() // prints 1
  embedo.Do() // prints 2
}

https://play.golang.org/p/ArqKESVWoS-

Мне любопытно понять, почему я должен явно передать существующий экземпляр Embedii типу Embedder, чтобы это работало правильно

Ответы [ 2 ]

4 голосов
/ 10 марта 2020

В Embedii.Do() получатель является значением указателя. Это копия. Присвоение чего-либо этой переменной указателя просто изменяет копию.

y = new(Embedii) просто назначает указатель на локальную переменную y, а когда Do() возвращается, оно теряется. При повторном вызове y будет снова nil, поэтому он создает и присваивает ему новое значение (которое снова будет потеряно после возврата).

Работает, если вы создаете Embedii до потому что тогда вы не создадите и не назначите его в Do() (что будет потеряно).

Если вы вернете новый Embedii (точнее, его адрес) и назначите его, вы увидите его увеличивается, но начинается с 0, а не 1, потому что первый вызов просто создает его без увеличения, а в других случаях он уже существовал, и поэтому первый вызов увеличивается сразу:

func (y *Embedii) Do() *Embedii {
    if y == nil {
        y = new(Embedii)
    } else {
        *y = *y + 1
    }
    fmt.Println(*y)
    return y
}

И используя его:

embedder := new(Embedder)
embedder.Embedii = embedder.Do() // prints 0
embedder.Embedii = embedder.Do() // prints 1

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

1
2
---
0
1
---
1
2
0 голосов
/ 10 марта 2020

"это должно появиться в типе, который его встраивает?" да, должно быть, потому что это другой тип внутри структуры.

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