Я хотел бы объявить общий класс, который содержит / получает переменную типа Any?
, но при запросе преобразует эту переменную в данный тип. Что-то вроде этого
class A<T> {
var o: NSObject!
var k: String!
var v: T {
get { return o.value(forKeyPath: k) as! T }
set { o.setValue(newValue, forKeyPath: k) }
}
}
Я хотел бы, чтобы это работало так, чтобы когда o.value(forKeyPath: k)
равно nil
и T
мог удерживать nil
(это ExpressibleByNilLiteral
), v
возвращает nil
(типа T
). Как бы то ни было, он вылетает из-за as!
. Можно ли сделать это?
Попытка взломать это выглядит так (предложено Как сделать вычисляемое свойство универсального класса зависимым от ограничений класса)
class A<T> {
var o: NSObject!
var k: String!
var v: T {
get {
let x = o.value(forKeyPath: k)
if let E = T.self as? ExpressibleByNilLiteral.Type {
if let x = x { return x as! T }
let n: T = <nil of type T> <---- not sure what to put here
return n
} else {
return x as! T
}
}
set { o.setValue(newValue, forKeyPath: k) }
}
}
Но я не уверен, как заставить его работать.
1 ответ
Не знаю почему, но это действительно работает
func cast<T>(_ v: Any?)->T {
if let E = T.self as? ExpressibleByNilLiteral.Type {
if let v = v {
return v as! T
} else {
return E.init(nilLiteral: ()) as! T
}
} else {
return v as! T
}
}
Я думал, что уже пробовал это, и это не сработало ... В любом случае, теперь мы можем заменить все вызовы as!
на cast
, когда мы не хотим сбой на nil
, если тип мы кастинг можем взять, например в получателе моего вопроса.
Похожие вопросы
Связанные вопросы
Новые вопросы
swift
Swift — это язык программирования общего назначения, разработанный Apple Inc., впервые выпущенный в 2014 году для своих платформ и Linux. Swift имеет открытый исходный код. Используйте тег только для вопросов о языковых функциях или необходимости кода в Swift. Используйте теги [ios], [ipados], [macos], [watch-os], [tvos], [swiftui], [cocoa-touch] и [cocoa] для (не зависящих от языка) вопросов о платформах или рамки.
Optional
будет соответствоватьExpressibleByNilLiteral
. Для этого требуется толькоinit(nilLiteral: ())
, и мы можем написатьlet n: T = E.init(nilLiteral: ()) as! T
(хотя комментарий в исходном коде для Optional, кажется, препятствует этому). К сожалению, это дает сбой, потому чтоE.init(nilLiteral: ())
...nil
иas!
не работает. Это работает для любого протокола, который предоставляет какой-тоinit
, который может быть вызван. Но реализацияas!
"запутана" сExpressibleByNilLiteral
, и вопрос в том, как их разделить.