Набор методов которые являются интерфейсом данного типа.
Method sets любого именованного типа T
состоит из всех методов с типом получателя(receiver) T
.
Method sets типа указателя *T
состоит из всех методов с типом получателя(receiver) T
и *T
.
Не разрешены методы для именованных типов, которые сами являются типами указателей:
type P *int
func (P) f() {} // ошибка компиляции
Вызов методов
Имя метода: (*Point).ScaleBy
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
Может быть вызван:
// 1
r := &Point{1; 2}
r.ScaleBy(2)
// 2
p := Point{1; 2}
pttr := &p
pttr.ScaleBy(2)
// 3
p := Point{1; 2}
(&p).ScaleBy(2)
Если получатель p
является переменной типа Point
, но методу необходим получатель *Point
, можно использовать сокращенную запись: p.ScaleBy(2)
При которой компилятор выполнит неявное получение адреса &p
этой переменной.
Это работает только для addressable переменных, включая поля структур наподобие p.X
и элементы массивов или срезов наподобие perim[0]
.
Так же работает наоборот:
(*pttr).ScaleBy(2)
pttr.ScaleBy(2)
Элементы map
Элементы map
являются не адресуемыми(not addressable). По этому получить адрес переменой и вызвать метод с получателем типа указатель нельзя. А вот наоборот, разыменовать указатель(dereference pointer) можно.
https://go.dev/play/p/LdnaJ9as_9H
package main
import (
"fmt"
)
type Point struct{
X float64
Y float64
}
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
func (p Point) String() string {
return fmt.Sprintf("X:%.2f;Y:%.2f", p.X, p.Y)
}
func main() {
// lists := map[string]Point{}
// lists["primes"].ScaleBy(7.7)
// cannot call pointer method on lists["primes"]
// cannot take the address of lists["primes"]
lists := map[string]*Point{}
lists["primes"] = new(Point)
lists["primes"].ScaleBy(7.7)
s := lists["primes"].String()
fmt.Println(s)
}
Интерфейсы
Значения интерфейса, так же, как у map
, не адресуемое(not addressable). По этому работают те же правила.
https://play.golang.org/p/pGtW_bodOKt
package main
import (
"fmt"
)
type Point struct{
X float64
Y float64
}
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
func (p Point) String() string {
return fmt.Sprintf("X:%.2f;Y:%.2f", p.X, p.Y)
}
type Scaler interface{
ScaleBy(float64)
}
func main() {
p := Point{1, 2}
// Тип значения Point
// var s Scaler = p // Ошибка. Т.к. значения интерфейса не адресуемое, то неявно получить указатель(*Point) и использовать его method sets не получится.
// cannot use p (type Point) as type Scaler in assignment
// Point does not implement Scaler (ScaleBy method has pointer receiver)
// s.ScaleBy(1.2)
//var str fmt.Stringer = p // Работает. У String() тип получателя Point
//fmt.Println(str.String())
// Тип значения *Point
var s Scaler = &p // Работает. У ScaleBy(float64) тип получателя *Point
s.ScaleBy(1.2)
var str fmt.Stringer = &p // Работает. Есть возможность неявно разыменовать указатель и использовать method sets типа Point
fmt.Println(str.String())
}
+----------------+-----------------------------------------------------------------------------------+
| Тип переменной | Тип получателя |
| +---------------------------+-----------------------------+-------------------------+
| | Вызов метода у переменной | Вызов метода у значения map | Присваивание интерфейсу |
+----------------+---------------------------+-----------------------------+-------------------------+
| Т | T|*T | T | T |
+----------------+---------------------------+-----------------------------+-------------------------+
| *T | T|*T | T|*T | T|*T |
+----------------+---------------------------+-----------------------------+-------------------------+