Swift 使用通用枚举和通用协议进行类型擦除
Swift Type Erasure with Generic Enum and Generic Protocol
我不得不在 Swift 中使用类型擦除几次,但它总是涉及通用协议。在这种情况下,它涉及通用枚举 and 和通用协议,我很困惑。
这是我的通用枚举和带有必要扩展的通用协议:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<[Model]> { get set }
}
extension ModelsDelegate {
func getNewState(state: UIState<[Model]>) -> UIState<[Model]> {
return state
}
func setNewState(models: UIState<[Model]>) {
state = models
}
}
这是我删除的通用类型 class:
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<[T]> {
get { return _getNewState(UIState<[T]>) } // Error #1
set { _setNewState(newValue) }
}
private let _getNewState: ((UIState<[T]>) -> UIState<[T]>)
private let _setNewState: (UIState<[T]> -> Void)
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = models.getNewState
_setNewState = models.setNewState
}
}
我收到以下错误(它们在代码示例中已标记):
错误 #1:
Cannot convert value of type '(UIState<[T]>).Type' (aka 'UIState<Array<T>>.Type') to expected argument type 'UIState<[_]>' (aka 'UIState<Array<_>>')
我已经为此工作了一段时间,"almost worked" 这段代码有很多变体。错误 always 与 getter.
有关
导致此错误的问题,如 ,是在这一行中您试图将类型作为参数传递,而不是该类型的实例:
get { return _getNewState(UIState<[T]>) }
但是,我首先要质疑你对这个函数使用参数,当然获取函数应该根本没有参数吗?在这种情况下,您只需要 _getNewState
函数具有签名 () -> UIState<[T]>
,并像这样调用它:
get { return _getNewState() }
此外,如果您的协议扩展中的 getNewState
和 setNewState(_:)
函数仅用于将您的 state
属性 的获取和设置转发给类型-erasure——你可以通过完全摆脱它们来简化你的代码,并在类型擦除的 init
中使用闭包表达式来代替:
_getNewState = { models.state }
_setNewState = { models.state = [=12=] }
(这些通过捕获对 models
参数的引用来工作,有关更多信息,请参阅 Closures: Capturing Values)
最后,我怀疑你的意思是在整个代码中引用 UIState<T>
而不是 UIState<[T]>
,因为 T
在这种情况下指的是数组中的一个元素,你的 .Success
case 有一个关联值(除非你在这里想要一个二维数组)。
总而言之,通过上述提议的更改,您会希望您的代码看起来像这样:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<Model> { get set }
}
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<T> {
get { return _getNewState() }
set { _setNewState(newValue) }
}
private let _getNewState: () -> UIState<T>
private let _setNewState: (UIState<T>) -> Void
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = { models.state }
_setNewState = { models.state = [=13=] }
}
}
我不得不在 Swift 中使用类型擦除几次,但它总是涉及通用协议。在这种情况下,它涉及通用枚举 and 和通用协议,我很困惑。
这是我的通用枚举和带有必要扩展的通用协议:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<[Model]> { get set }
}
extension ModelsDelegate {
func getNewState(state: UIState<[Model]>) -> UIState<[Model]> {
return state
}
func setNewState(models: UIState<[Model]>) {
state = models
}
}
这是我删除的通用类型 class:
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<[T]> {
get { return _getNewState(UIState<[T]>) } // Error #1
set { _setNewState(newValue) }
}
private let _getNewState: ((UIState<[T]>) -> UIState<[T]>)
private let _setNewState: (UIState<[T]> -> Void)
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = models.getNewState
_setNewState = models.setNewState
}
}
我收到以下错误(它们在代码示例中已标记):
错误 #1:
Cannot convert value of type '(UIState<[T]>).Type' (aka 'UIState<Array<T>>.Type') to expected argument type 'UIState<[_]>' (aka 'UIState<Array<_>>')
我已经为此工作了一段时间,"almost worked" 这段代码有很多变体。错误 always 与 getter.
有关导致此错误的问题,如
get { return _getNewState(UIState<[T]>) }
但是,我首先要质疑你对这个函数使用参数,当然获取函数应该根本没有参数吗?在这种情况下,您只需要 _getNewState
函数具有签名 () -> UIState<[T]>
,并像这样调用它:
get { return _getNewState() }
此外,如果您的协议扩展中的 getNewState
和 setNewState(_:)
函数仅用于将您的 state
属性 的获取和设置转发给类型-erasure——你可以通过完全摆脱它们来简化你的代码,并在类型擦除的 init
中使用闭包表达式来代替:
_getNewState = { models.state }
_setNewState = { models.state = [=12=] }
(这些通过捕获对 models
参数的引用来工作,有关更多信息,请参阅 Closures: Capturing Values)
最后,我怀疑你的意思是在整个代码中引用 UIState<T>
而不是 UIState<[T]>
,因为 T
在这种情况下指的是数组中的一个元素,你的 .Success
case 有一个关联值(除非你在这里想要一个二维数组)。
总而言之,通过上述提议的更改,您会希望您的代码看起来像这样:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<Model> { get set }
}
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<T> {
get { return _getNewState() }
set { _setNewState(newValue) }
}
private let _getNewState: () -> UIState<T>
private let _setNewState: (UIState<T>) -> Void
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = { models.state }
_setNewState = { models.state = [=13=] }
}
}