Comments 7
Эм, ожидал что последним абзацем будет листинг кода с проверкой при которой результатом выполнения будет fmt.Println("f null")
Держите:
package main
import "fmt"
type Word struct {
name string
priority uint
}
type Foo interface {
foo()
}
func (w *Word) foo() {
fmt.Println("call foo()")
}
func (w *Word) noFoo() {
fmt.Println("call noFoo()")
}
func call(f Foo) {
if f != (*Word)(nil) {
f.foo()
} else {
fmt.Println("f null")
}
}
func main() {
var f1 *Word
call(f1)
}
Такой себе пример. А если у вас два типа реализующих интерфейс и в call передали указатель другой?
А код изначально не корректен. В функции call
вообще не должно быть проверки на nil
.
Проверку на nil
скорее стоит поставить внутри метода foo
, например чтоб вернуть zero value, как вариант, если метод что-то должен вернуть. Либо ошибку, и вот её уже стоит проверять в функции call
.
Порекомендуйте, пожалуйста, какие-нибудь материалы на тему best-practices по избеганию null pointer dereference. Не так давно пишу на го и постоянно сталкиваюсь с этой бедой. Стараюсь поменьше использовать указатели, но все равно...
Вряд ли есть много структурированой информации на эту тему. Думаю, если функция возвращает результат+error, всегда нужно проверять error, и, если error != nil, не использовать результат. И свой код писать так же, если возвращаете результат и пустой error, результат должен быть не nil. Также всегда стоит быть уверенным, что была выделена память под slice или map прежде чем писать туда данные, так как slice и map это всегда неявный указатель. Если не уверены, лучше сделать проверку на nil и вызвать make.
Анатомия интерфейсов в Go