Wątek przeniesiony 2021-09-16 09:49 z Inne języki programowania przez cerrato.

Golang pytanie odnośnie interfejsów i pointerów.

0

Cześć ! Pytanie odnośnie tego przykłądu https://tour.golang.org/methods/9 . Dlaczego a = f jest ok, a=&v jest ok a nawet a = &f jest ok ale a = v wywala błąd. Rozumiem zasady ale nie rozumiem dlaczego tak to działa. Prosze o jakieś proste wytłumaczenie.

1

Mamy dwie implementacje interfejsu Abser - jedną dla typu MyFloat oraz drugą dla typu *Vertex (zwróć uwagę na referencję w nazwie typu):

func (f MyFloat) Abs() float64 { /* ... */ }
func (v *Vertex) Abs() float64 { /* ... */ }

Nie możemy przypisać typu Vertex do Abser, ponieważ nie mamy implementacji tamtego interfejsu dla samego Vertex (jedynie dla referencji).

Btw, zdaje się, że dokumentacja tłumaczy tę różnicę całkiem nieźle:

// In the following line, v is a Vertex (not *Vertex)
// and does NOT implement Abser.
0

To dlaczego a = &f działa poprwnie ?

1

BTW, dzisiaj na Packt jest za free ebook o Go: https://www.packtpub.com/packt/offers/free-learning

0

@Kamil Pyrkosz bo referencje są "podtypem" surowych wartości. Jak się zastanowisz, to ma to sens, bo jeśli masz coś takiego:

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
        tmp := v.X
        v.X = v.Y
        v.Y = tmp

	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

To nagle okazuje się to dość oczywiste. Jakiekolwiek zmiany dokonane w kopii danych, tj. jeśli masz (t T), nie "wyciekną" na zewnątrz. Jeśli przekazujesz przez referencję, tj. (t *T), to możesz zmodyfikować swoją strukturę, co w przypadku przekazania wartości do funkcji przyjmującej referencję, mogłoby skutkować nieoczekiwanymi wynikami.

0

Znalazłem coś takiego https://scene-si.org/2018/02/28/interfaces-in-go/ i było to w miare pomocne. Szczególnie 2 zasady umieszczone na końcu : You should never pass your objects without a pointer ;
You should never pass your interfaces with a pointer ; Ale nadal będę wdzięczny za wytłumaczenie tego konceptu dlaczego w https://tour.golang.org/methods/9 można zrobić a = &f ale a = v już nie można.

0

Jest jeszcze to https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html i zdaje się znacznie lepiej odpowiadać na moje pytanie, ale jako że jestem upośledzony to i tak prosiłbym o pomoc w wytłumaczeniu 3 zasad znajdujących się w podanym tekście.

The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T

The method set of any other type T consists of all methods with receiver type T.

The method set of the corresponding type T does not consists of any methods with receiver type *T.

1
Kamil Pyrkosz napisał(a):

Jest jeszcze to https://www.ardanlabs.com/blog/2014/05/methods-interfaces-and-embedded-types.html i zdaje się znacznie lepiej odpowiadać na moje pytanie, ale jako że jestem upośledzony to i tak prosiłbym o pomoc w wytłumaczeniu 3 zasad znajdujących się w podanym tekście.

The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T

Jako bazowy przykład:

// Założmy, że to elektryczny, bo nie chce mi się jakiegoś Fuelling robić
struct Car {
}

func(c Car) Drive() {
 fmt.Println("driving")
}

func(c *Car) Charge() {
  fmt.Println("charging")
}

Ten method set odnosi się do jednej i drugiej metody struktury Car - bez względu na to, czy jest to value czy value as a pointer (czyli po prostu pointer do pamięci). Tzn: jak kompilator wymaga takiego zbioru metod, to zaakceptuje obie (tu bez znaczenia, czy nie spowoduje to problemu działania w sytuacji, gdy chcemy instancje tej struktury modyfikować (c *Car) czy tylko odczytywać (c Car)

The method set of any other type T consists of all methods with receiver type T.

Jak w powyższym przykładzie, ale kompilator weźmie pod uwagę tylko metody bez pointera (czyli tylko Drive)

The method set of the corresponding type T does not consists of any methods with receiver type *T.

To odnosi się do przykładu Williama - podał case, że jedna z metod posiadała pointera, natomiast według tej zasady kompilator tego się nie "spodziewa" (nie wiem czy to dobre określenie tutaj), stąd błąd kompilacji.

Nie wiem czy dobrze Ci to objaśniłem, ale kwestie value/pointer receiverów lepiej np. zobaczyć tutaj: https://flaviocopes.com/golang-methods-receivers/ bo William ma już takie mocniej skomplikowane przykłady zahaczające o internalsy, więc nie wiem czy na ten moment takimi chcesz się wzorować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1