Не удается преобразовать Expression‹Int› в Expression‹AnyObject›

Я использую библиотеку SQLite.swift.

У меня есть несколько Expression,

let idColumn = Expression<Int>("id")
let nameColumn = Expression<String>("name")

Я хотел бы, чтобы словарь содержал их, поэтому я сделал:

let columns: [String: Expression<AnyObject>] = [
   "id": idColumn,
   "name": nameColumn
]

Но я получаю ошибку компилятора:

Cannot convert value of type 'Expression<Int>' to expected dictionary value type 'Expression<AnyObject>'

Почему эта ошибка? Почему тип Int не может быть AnyObject?

Я также пробовал Any вместо AnyObject:

let columns: [String: Expression<Any>] = [
       "id" : idColumn,
       "name": nameColumn
    ]

Аналогичная ошибка показывает:

Cannot convert value of type 'Expression<Int>' to expected dictionary value type 'Expression<Any>'

Я не понимаю этого... Может кто-нибудь объяснить мне?


person Leem    schedule 15.11.2017    source источник
comment
Expression<Int> и Expression<Any> — это разные типы, и приведение типов не работает с ограниченными универсальными типами. Почему бы вам не объявить idColumn и nameColumn как Expression<Any>?   -  person Dávid Pásztor    schedule 15.11.2017
comment
У меня нет опыта работы с SQLite.swift (или SQLite), но это похоже на их cast(_:) предназначена для. Обобщения в общем случае неизменны.   -  person Hamish    schedule 15.11.2017
comment
Поскольку дженерики в целом не ковариантны по своему параметризованному типу. Наследование/полиморфизм не применяется.   -  person matt    schedule 15.11.2017


Ответы (2)


Ваши ожидания ошибочны; то, что вы ожидаете, — это не то, как работает язык Swift. Я просто повторю пример, который привожу в своей книге:

Универсальный тип, специализированный для подтипа, не является полиморфным по отношению к тому же универсальному типу, специализированному для супертипа. Например, предположим, что у нас есть простая универсальная структура вместе с классом и его подклассом:

struct Wrapper<T> {
}
class Cat {
}
class CalicoCat : Cat {
}

Затем вы не можете назначить Wrapper, специализированный для CalicoCat, где ожидается специализированный Wrapper для Cat:

let w : Wrapper<Cat> = Wrapper<CalicoCat>() // compile error

Технически мы говорим, что дженерики не являются ковариантными относительно их параметризованного типа. Из этого правила есть исключения — очевидное из них — необязательное, — но они должны быть встроены в сам язык.

person matt    schedule 15.11.2017

Голые типы Int и String могут быть преобразованы в AnyObject. Но это не применяется, когда они обернуты в общий тип: Expression<Int> нельзя преобразовать в Expression<AnyObject>. Вот как Swift работает сегодня (Swift 4):

// OK
let i: Int = 1
let i2 = i as AnyObject

// Error: cannot convert value of type 'S<Int>' to type 'S<AnyObject>' in coercion
struct S<T> { }
let s = S<Int>()
let s2 = s as S<AnyObject>

Кроме того, даже если бы это было так, выражения, которые вы бы извлекли из словаря, потеряли бы свой тип столбца: вы не могли бы использовать их непосредственно в SQLite.swift, как показано на вашем другой вопрос.

person Gwendal Roué    schedule 15.11.2017