Интерфейсное значение можно рассматривать как пару из значения и конкретного типа:
(value, type)
Интерфейсное значение содержит значение конкретного нижележащего типа.
Вызов метода интерфейсного значения выполняет метод с таким же именем у его нижележащего типа.
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
Вывод:
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
Интерфейсные значения с нижележащим типом nil
Если нижележащим значением интерфейсного значения является nil, то метод будет вызван с получателем nil.
В некоторых языках это привело бы к исключению нулевого указателя, но в Go обычно пишут методы, которые обрабатывают ситуацию, когда они вызваны с получателем nil (как в случае с методом M в следующем примере).
Обратите внимание, что если интерфейсное значение имеет nil в качестве нижележащего значения, то само по себе оно не nil.
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("
Вывод:
(
Интерфейсное значение nil
Интерфейсное значение nil не содержит ни значения, ни конкретного типа.
Вызов метода у nil интерфейса является ошибкой времени выполнения, т.к. внутри пары значение/тип нет типа, чтобы указать, какой конкретный метод надо вызвать. (В примере приводится ошибка при исполнении кода в песочнице)
package main
import "fmt"
type I interface {
M()
}
func main() {
var i I
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
Вывод:
(
Пустой интерфейс
Интерфейс, который не содержит ни одного метода называется пустым интерфейсом:
interface{}
Пустой интерфейс может содержать значение любого типа. (Каждый тип реализует по меньшей мере нуль методов.)
Пустые интерфейсы используются в коде, где необходимо работать со значениями неизвестного типа. Например, fmt.Print принимает любое количество аргументов типа interface{}.
package main
import "fmt"
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
Вывод:
(
Читайте также:
Комментариев нет:
Отправить комментарий