Почему я могу напрямую протестировать интерфейс на соответствие значению? - PullRequest
0 голосов
/ 10 января 2020

К моему удивлению, это скомпилировано (и работает) нормально с Go 1.13:

var v interface{}
if v == "" { // false
    fmt.Println("v is empty string")
}

У меня всегда было впечатление, что мне нужно сделать переключатели типа и / или утверждение, прежде чем я смогу провести такой тест , И тыкаю немного больше на Go игровую площадку :

v = 0
if v == 0 { // True
    fmt.Println("v is 0")
}
type myType struct {
    a string
    b int
}
v = myType{}
// Only works if myType is comparable
if v == (myType{}) { // true
    fmt.Println("v is empty myType")
}

Может кто-нибудь сказать мне, почему это законно? Безопасно ли полагаться на это поведение? Например, если я хочу проверить, является ли переменная пустой строкой, нулевым целым числом или числом с плавающей запятой:

func isZero(v interface{}) bool {
    return v == "" || v == 0 || v == 0.0
}

Может ли это вызвать у меня проблемы?

Ответы [ 2 ]

6 голосов
/ 10 января 2020

Спецификация объясняет , почему сравнения допустимы:

Значение x неинтерфейсного типа X и значение t интерфейсного типа T сравнимы, когда значения типа X сопоставимы, а X реализует T. Они равны, если тип Dynami c t идентичен X, а значение Dynami c t равно x.

Это утверждение относится к примеру в вопрос, потому что все типы реализуют интерфейс interface{}.

5 голосов
/ 10 января 2020

spe c говорит об операторах сравнения:

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

Операторы равенства == и! = Применяются к операндам, которые сравнимы. Операторы упорядочения <, <=,> и> = применяются к упорядоченным операндам. Эти термины и результат сравнений определены следующим образом:

  • Значение x неинтерфейсного типа X и значение t интерфейсного типа T сравнимы, когда значения типа X сравнимы и X реализует T. Они равны, если тип Dynami c т идентичен X, а значение Dynami c Т равно х.

(я удалил все остальные пункты; перейдите по ссылке для полного списка.)

Ваш v имеет тип interface{}, поэтому Сначала задайте следующие вопросы:

  • Есть ли в x пустой интерфейс? (Да, это так.)
  • Сравнимо ли x? (Это для строки и целого.)

Затем, если сравнение разрешено, код компилируется; поэтому во время выполнения мы спрашиваем:

  • Имеет ли v тип x dynamici c? Если да, является ли его значение Dynami c равным?

Если оба значения истинны, x равно v; в противном случае x не равно v.

(ваш пример кода)

func isZero(v interface{}) bool {
    return v == "" || v == 0 || v == 0.0
}

Если v содержит float32 или int64 или какой-то другой разумный тип, у нас могут быть проблемы.

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