Как применить к псевдониму типа в Go?

Смотрите этот фрагмент детской площадки.

Соответствующий код:

type somethingFuncy func(int) bool

func funcy(i int) bool {
    return i%2 == 0
}

var a interface{} = funcy

func main() {

    _ = a.(func(int) bool)  // Works

    fmt.Println("Awesome -- apparently, literally specifying the func signature works.")

    _ = a.(somethingFuncy)  // Panics

    fmt.Println("Darn -- doesn't get here. But somethingFuncy is the same signature as func(int) bool.")
}

Первый отбор работает, явно объявляя тип. Но вторая личная паника. Зачем? Есть ли чистый способ бросить более длинную подпись подписи?

Ответы

Ответ 1

TL;DR

Для утверждений типа (которые вы используете) имеет значение только фактический тип. Таким образом, somethingFuncy равен только somethingFuncy, а не func(int) bool.

Объяснение

Для начала это не имеет никакого отношения к кастингу. В игре нет кастинга. Существуют типы утверждений и типы конверсий.

Вы имеете дело с утверждением типа и считаете, что выполняются те же условия как для типов конверсий. Я сделал ту же ошибку, читая ваш вопрос, но на самом деле существует огромная разница в поведении.

Предположим, что у вас есть два типа, скажем int и type MyInt int. Они являются конвертируемыми, поскольку они оба использовать один и тот же базовый тип (одно из правил преобразования), поэтому это работает (play):

var a int = 10
var b MyInt = MyInt(a)

Теперь предположим, что a не имеет тип int, а типа interface{} (play):

var a interface{} = int(10)
var b MyInt = MyInt(a)

Компилятор скажет вам:

не может преобразовать (type interface {}), чтобы ввести MyInt: require type assertion

Итак, теперь мы больше не делаем конверсии, а утверждения. Мы должны это сделать (play):

var a interface{} = int(10)
var b MyInt = a.(MyInt)

Теперь у нас та же проблема, что и в вашем вопросе. Это утверждение терпит неудачу с этой паникой:

panic: преобразование интерфейса: интерфейс is int, а не main.MyInt

Причина этого указана в разделе типа утверждения спецификации:

Для выражения x типа интерфейса и типа T первичное выражение x.(T)утверждает, что x не nil и что значение, хранящееся в x, имеет тип T. Обозначение x.(T) называется утверждением типа. Точнее, если T не является типом интерфейса, x.(T) утверждает, что динамический тип x идентичен типу T.

Итак, int должен быть идентичен MyInt. В правилах type identity указано, что (среди других правил):

Два именованных типа идентичны, если их имена типов возникают в том же TypeSpec.

Поскольку int и MyInt имеют разные объявления (TypeSpecs), они не равны и утверждение терпит неудачу. Когда вы утверждаете a - int, это утверждение работает. То, что вы делаете, невозможно.

Бонус:

Фактическая проверка происходит в в этом коде, который просто проверяет, являются ли оба типа то же, что и ожидалось.

Ответ 2

Чтобы завершить nemo awesome answer, обратите внимание, что, хотя вы не можете напрямую перейти от интерфейса (ef, interface{}) к заданному динамическому типу (например, int) к другому типу (например, type MyInt int), вы можете выполнить два шага один за другим:

  • утверждают, что динамический тип вашей переменной - это то, что вы ожидаете от нее;
  • преобразует результат этого утверждения в выбранный вами тип.

Обратите внимание, что поскольку базовый тип, как следует из его названия, является динамическим, рекомендуется проверить, было ли утверждение типа успешным или неудачным. С другой стороны, правильность преобразования типов выполняется компилятором.

Ниже приведен фрагмент вашей игровой площадки: http://play.golang.org/p/FZv06Zf7xi

Ответ 4

Обновление 2017:

С утверждениями типа в Go 1.9 вы можете просто добавить =, где вы определяете тип.

type somethingFuncy = func(int) bool

Это говорит компилятору, что somethingFuncy является альтернативным именем для func(int) bool.