Golang не требует явных реализаций интерфейса.Что вы делаете здесь:
type loopBack struct {
net.Conn
buf bytes.Buffer
}
Это похоже на:
type loopBack struct{
Conn net.Conn
buf bytes.Buffer
}
net.Conn
, являющийся типом интерфейса, первое поле вашего типа loopBack
может быть любым, что реализуетинтерфейс net.Conn
, который, конечно, больше, чем Read
и Write
( см. здесь ).
Преимущество типов вложения заключается в том, что поля и функции-получатели (кроме конфликтов имен) можно напрямую обращаться к типам, которые их встраивают.
Со встроенным полем net.Conn
вы действительно можете написать:
loop.Write(nil)
Если поле Conn
инициализируется (в противном случае его значение равно nil
).Если изменить объявление на вторую версию, loop.Write
не сработает, вам придется написать:
loop.Conn.Write(nil)
Внедрение шрифтов очень мощное, но при первом запуске у вас есть ряд ошибок.К счастью, есть целый параграф, объясняющий встраивание в эффективный документ go
В любом случае, как уже говорилось, вы можете вызывать функции и обращаться к полям (если вы вместо этого встраиваете тип структурыинтерфейса).Однако есть одна вещь: поле должно быть правильно инициализировано!
И именно здесь вы ошиблись: вам все равно придется инициализировать вашу Conn
часть переменной loopBack
,в противном случае вы делаете то же самое, что и:
net.Conn(nil).Write(nil)
Что, естественно, приводит к панике (разыменование нулевого указателя) ...
Например:
conn, err := net.Dial("tcp", "localhost:80")
if err != nil {
log.Fatalf("failed to dial localhost: %+v", err)
}
loop := loopBack{
Conn: conn,
}
loop.Write(nil) // same as conn.Write(nil)
Неспособность установить встроенное поле net.Conn
сродни выполнению чего-то вроде этого:
s := make([]*int, 10) // make slice of 10 pointers to int
fmt.Println(len(s)) // outputs 10
*s[0]++ // add 1 to first element PANICS
10 элементов в срезе существуют, но все они были инициализированы в nil