繁体   English   中英

具有通用枚举和通用协议的Swift类型擦除

[英]Swift Type Erasure with Generic Enum and Generic Protocol

我不得不在Swift中使用几次类型擦除,但是它总是涉及通用协议。 在这种情况下,它包含了一个通用的枚举和通用的协议和我难倒。

这是我的通用枚举和通用协议,带有必要的扩展名:

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 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<_>>')

我已经为此工作了一段时间,并且“几乎可以正常工作”的此代码有很多变体。 该错误始终与吸气剂有关。

正如@dan所指出的 ,导致此错误的问题是,在此行上,您尝试传递类型作为参数,而不是该类型的实例:

get { return _getNewState(UIState<[T]>) }

但是,我首先会质疑您对该函数使用参数,因此,获取函数肯定根本没有参数吗? 在这种情况下,您只希望_getNewState函数具有签名() -> UIState<[T]> ,并按如下方式调用它:

get { return _getNewState() }

另外,如果协议扩展中的getNewStatesetNewState(_:)函数仅存在以便将state属性的获取和设置转发给类型擦除,则可以通过完全删除它们并使用闭包来简化代码类型擦除的init中的表达式:

_getNewState = { models.state }
_setNewState = { models.state = $0 }

(这些工作通过捕获对models参数的引用来获得,有关更多信息,请参见Closures:捕获值 )。

最后,我怀疑您的意思是在整个代码中都引用UIState<T>而不是UIState<[T]> ,因为在这种情况下, T引用.Success大小写具有关联值的数组中的元素(除非您想在此处使用2D数组)。

总而言之,通过上述建议的更改,您将希望代码看起来像这样:

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 = $0 }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM