swift - 为什么这会造成这么多麻烦? (相关类型的协议(protocol)和类型别名)

标签 swift swift3

我正在尝试做一些类似的事情:

protocol Protocol {
    associatedtype T
    associatedtype ArrayT = Array<T>
}

struct Struct<ProtocolType: Protocol> {

    func doSomething(with: ProtocolType.ArrayT) {

        let _ = with.map { $0 } 
        // ^ compiler complains on this line
        // "value of type ProtocolType.ArrayT has no member map"
    }
}   

其中我定义了一个使用 linkedtype T 的便利类型别名 ArrayT。似乎当我尝试像 doSomething(_:) 中那样使用 ArrayT 时,我丢失了 ArrayT< 的 Array 类型信息

ArrayT 不应该绝对是一个 Array 并因此成为 Sequence 协议(protocol)的成员,从而公开 map 功能? 🤔

我现在采用的工作解决方案是在协议(protocol)之外定义一个通用类型别名:

typealias ProtocolArray<ProtocolType: Protocol> = Array<ProtocolType.T>

struct Struct<ProtocolType: Protocol> {

    func doSomething(with: ProtocolArray<ProtocolType>) {
        let _ = with.map { $0 } // no complaints
    }
}

我在这里缺少什么?

最佳答案

线路associatedtype ArrayT = Array<T>仅告诉编译器 ArrayT默认值Array<T> 。协议(protocol)的改编仍然可以改变 ArrayT像:

struct U: Protocol {
    typealias T = UInt32
    typealias ArrayT = UInt64   // <-- valid!
}

如果您想要固定类型,则应该使用类型别名...

// does not work yet.
protocol Protocol {
    associatedtype T
    typealias ArrayT = Array<T>
}

但是编译器提示类型太复杂🤷。因此,您能做的最好的事情就是限制 ArrayT成为序列/集合/等,并希望适配器不会自行更改类型。

// still somewhat off
protocol Protocol {
    associatedtype T
    associatedtype ArrayT: Sequence = [T]
}

但是请注意,序列可以有任何元素类型,但我们希望 ArrayT 的元素必须是 T。我们不能附加 where关联类型的子句:

// fail to compile: 'where' clause cannot be attached to an associated type declaration
associatedtype ArrayT: Sequence where Iterator.Element == T = [T]

相反,您需要在每次使用协议(protocol)时设置此约束:

struct Struct<ProtocolType: Protocol> 
    where ProtocolType.ArrayT.Iterator.Element == ProtocolType.T {

完整的工作代码:

protocol Protocol {
    associatedtype T
    associatedtype ArrayT: Sequence = [T]
//                       ^~~~~~~~~~
}

struct Struct<ProtocolType: Protocol> 
    where ProtocolType.ArrayT.Iterator.Element == ProtocolType.T 
//  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
    func doSomething(w: ProtocolType.ArrayT) {
        let _: [ProtocolType.T] = w.map { $0 }
    }
}

关于swift - 为什么这会造成这么多麻烦? (相关类型的协议(protocol)和类型别名),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39629358/

相关文章:

swift - 无法将字符串转换为双 Swift

Swift 序列协议(protocol)的 Swift 2 到 3 迁移

swift - 使用组合的自定义更改运算符

swift - 如何根据 Swift 中的数组条目构造 alamofire 查询?

ios - 更改 slider 上的动画速度

swift - 非'@objc'方法不满足'@objc'协议(protocol)的可选要求

ios - TableView - heightForRowAtIndexPath 未被调用

swift - `sum` 测量序列扩展

ios - 将数据从 tableviewcontroller 发送到 detailviewcontroller

ios - 在函数 cellForRowAt 中访问静态单元格的 detailTextLabel