Сравнение пустых интерфейсов в Голанге - PullRequest
0 голосов
/ 02 января 2019

Согласно спецификации :

Значения интерфейса сопоставимы.Два значения интерфейса равны, если они имеют идентичные динамические типы и одинаковые динамические значения или оба имеют значение nil.

var err error 
var reader io.Reader                           

Насколько мы понимаем, err и reader имеют разные динамические типы(error и io.Reader) и, следовательно, не сопоставимы.

fmt.Println(err == reader) 

приведет к ошибке компиляции:

недопустимая операция: err == читатель (ошибка несовпадения типов и io.Reader)

Еслиэто правда, почему команда Println выводит одинаковые результаты для обеих переменных?Почему оба nil?

fmt.Printf("reader: %T", reader) // nil
fmt.Printf("error: %T", err) // nil

EDIT reflect.TypeOf(err) или reflect.TypeOf(reader) также будут выводить nil.Я не понимаю, почему вывод одинаков, если типы разные.

1 Ответ

0 голосов
/ 02 января 2019

Это правда, что значения интерфейса сопоставимы, но вы можете сравнивать только те значения, которые назначаются друг другу (точнее, одно назначается другому). Цитирование из Spec: Операторы сравнения:

В любом сравнении, первый операнд должен быть присваиваемым типу второго операнда или наоборот.

Вы не можете присвоить значение error для io.Reader, и вы не можете присвоить значение io.Reader для error, поэтому вы не можете их сравнить.

Они могут хранить или не хранить одно и то же динамическое значение. Если вы хотите сравнить их, сначала закройте оба к interface{}, чтобы вы могли сравнить их, например ::

fmt.Println(interface{}(err) == interface{}(reader))

Будет выведено (попробуйте на Go Playground ):

true

Примечание: на самом деле было бы достаточно преобразовать только одно из них в interface{}, потому что таким образом другое значение станет сопоставимым с типом того значения, которое вы преобразовали в interface{} (любое значение может быть преобразовано в interface{}), так что было бы достаточно сделать:

fmt.Println(interface{}(err) == reader)

Проверка сравнения с не nil значениями интерфейса:

type x int

func (x) Error() string            { return "" }
func (x) Read([]byte) (int, error) { return 0, nil }

err = x(0)
reader = x(0)
fmt.Println(interface{}(err) == interface{}(reader))

reader = x(1)
fmt.Println(interface{}(err) == interface{}(reader))

Теперь вывод будет (попробуйте на Go Playground ):

true
false

Также не забывайте, что значение интерфейса nil не равно значению интерфейса не nil, содержащему динамическое значение nil. Подробнее см. Сокрытие значений nil, понимание причины сбоя golang

Edit:

Пакет fmt печатает значение внутри интерфейса, а не значение интерфейса. Цитирование из пакета документов fmt:

Независимо от глагола, если операнд является значением интерфейса, используется внутреннее конкретное значение, а не сам интерфейс.

То же самое относится к reflect.TypeOf(): он возвращает динамический тип, но если вы передаете ему значение интерфейса nil, он возвращает nil, поэтому пакет fmt будет печатать nil. Цитирую свой документ:

TypeOf возвращает тип отражения, который представляет динамический тип i. Если i - нулевое значение интерфейса, TypeOf возвращает ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...