Таблица с фиксированным заголовком и первым столбцом (HTML, CSS, JS при необходимости)?

Проблема здесь в том, что shower - это тип interface. Типы интерфейсов в Go удерживают фактическое значение и его динамический тип. Подробнее об этом: Законы отражения # Представление интерфейса .

Выбранный фрагмент содержит 2 значения не nil. Второе значение представляет собой значение интерфейса, пару (значение; тип), содержащее значение nil и тип *display. Цитирование из спецификации языка g1] Go: Операторы сравнения :

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

blockquote>

Поэтому, если вы сравните его с nil, это будет false. Если вы сравните его со значением интерфейса, представляющим пару (nil;*display), это будет true:

if x == (*display)(nil) {
    panic("everything ok, nil found")
}

Это кажется неосуществимым, так как вам нужно знать, какой тип интерфейса имеет.

Почему это реализовано таким образом?

Интерфейсы, в отличие от других конкретных типов (не-интерфейсы), могут содержать значения разных типов конкретных типов (разные статические типы). Время выполнения должно знать динамический или runtime-тип значения, хранящегося в переменной типа интерфейса.

interface - это всего лишь набор методов, любой тип реализует его если одни и те же методы являются частью метода , заданного типа. Существуют типы, которые не могут быть nil, например struct или пользовательский тип с int в качестве базового типа. В этих случаях вам не нужно будет сохранять значение nil этого конкретного типа.

Но любой тип также включает конкретные типы, где nil является действительным (например, фрагменты, карты, каналы, все типы указателей), поэтому, чтобы сохранить значение во время выполнения, которое удовлетворяет интерфейсу, разумно поддерживать сохранение nil внутри интерфейса. Но помимо nil внутри интерфейса мы должны хранить его динамический тип, поскольку значение nil не несет такую ​​информацию. Альтернативным вариантом будет использование nil в качестве самого значения интерфейса, когда значение, которое будет храниться в нем, nil, но это решение недостаточно, так как оно потеряет информацию о динамическом типе.

Некоторые говорят, что интерфейсы Go являются динамически типизированными, но это вводит в заблуждение. Они статически типизированы: переменная типа интерфейса всегда имеет один и тот же статический тип, и хотя во время выполнения значение, хранящееся в переменной интерфейса, может изменять тип, это значение всегда будет удовлетворять интерфейсу.

blockquote>

В общем случае, если вы хотите указать nil для значения типа interface, используйте явное значение nil, а затем вы можете проверить равенство nil. Наиболее распространенным примером является встроенный тип error , который является интерфейсом с одним методом. Всякий раз, когда нет ошибки, вы явно устанавливаете или возвращаете значение nil, а не значение какой-либо конкретной (неинтерфейсной) ошибки типа типа (что было бы очень плохой практикой, см. Демонстрацию ниже).

В вашем примере путаница возникает из фактов, что:

  • вы хотите иметь значение в качестве типа интерфейса (shower)
  • , но значение, которое вы хотите хранить в срезе не тип shower, а конкретный тип

Поэтому, когда вы помещаете *display тип в срез shower, будет создано значение интерфейса, которое представляет собой пару (значение; тип), где значение равно nil, а тип - *display. Значение внутри пары будет nil, а не значением самого интерфейса. Если вы поместите значение nil в срез, то значение интерфейса себя будет nil, а условием x == nil будет true.

Демонстрация

См. этот пример: Игровая площадка

type MyErr string

func (m MyErr) Error() string {
    return "big fail"
}

func doSomething(i int) error {
    switch i {
    default:
        return nil // This is the trivial true case
    case 1:
        var p *MyErr
        return p // This will be false
    case 2:
        return (*MyErr)(nil) // Same as case 1
    case 3:
        var err error // Zero value is nil for the interface
        return err    // This will be true because err is already interface type
    case 4:
        var p *MyErr
        return error(p) // This will be false because the interface points to a
                        // nil item but is not nil itself.
    }
}

func main() {
    for i := 0; i <= 4; i++ {
        err := doSomething(i)
        fmt.Println(i, err, err == nil)
    }
}

Выход:

0  true
1  false
2  false
3  true
4  false

В случае 2 указатель nil но сначала он преобразуется в тип интерфейса (error), поэтому создается значение интерфейса, которое содержит значение nil и тип *MyErr, поэтому значение интерфейса не является nil.

0
задан user3190746 15 January 2019 в 17:12
поделиться