我想扩展Array,为一个新协议添加一致性——但仅适用于元素本身符合特定协议的array.

更一般地说,我希望具有类型参数的类型(无论是协议还是具体类型)只在类型参数匹配某些约束时实现协议.

从Swift 2.0开始,这似乎是不可能的.有什么我错过的吗?

实例

假设我们有Friendly个协议:

protocol Friendly {
    func sayHi()
}

我们可以扩展现有类型来实现它:

extension String: Friendly {
    func sayHi() {
        print("Greetings from \(self)!")
    }
}

"Sally".sayHi()

Array的元素都是Friendly时,我们还可以将其扩展为sayHi():

extension Array where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

["Sally", "Fred"].sayHi()

此时,类型[Friendly]本身应该实现Friendly,因为它满足协议的要求但是,此代码不编译:

extension Array: Friendly where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

错误消息是"带有约束的'Array'类型的扩展不能有继承子句",这似乎彻底关闭了直接方法的大门罢工>

是否有间接的解决方法?我能用些聪明的把戏吗?也许有一种方法需要将SequenceType而不是Array扩展罢工>

一个可行的解决方案将使这段代码得以编译:

let friendly: Friendly = ["Foo", "Bar"]

Update:这已经登陆Swift 4.1,这是一件美丽的事情!

现在,extension Array: Friendly where Element: Friendly个示例按照原始问题中给出的方式编译.

推荐答案

编辑:正如更新的问题中所指出的,从Swift 4.1开始,现在就可以这样做了


这在Swift中目前是不可能的(从Xcode 7.1开始).如错误所示,您不能将协议一致性("继承子句")限制为受类型约束的扩展.也许有一天.我不认为有任何深层次的原因让这不可能,但它目前尚未实施.

最接近的方法是创建包装器类型,例如:

struct FriendlyArray<Element: Friendly>: Friendly {
    let array: [Element]
    init(_ array: [Element]) {
        self.array = array
    }
    func sayHi() {
        for elem in array {
            elem.sayHi()
        }
    }
}

let friendly: Friendly = FriendlyArray(["Foo", "Bar"])

(你可能想把FriendlyArray扩展成CollectionType.)

关于我自己堕落到试图实现这一目标的疯狂状态,以及我从边缘爬回来的故事,请参见NSData, My Old Friend.

Swift相关问答推荐

RealityKit(VisionOS)中的PhysicBodyComponent和DragGesture

通过SwiftUI中的列表 Select 从字典中检索值

了解SWIFT中的任务行为

一种函数,用于判断变量的类型是否为在SWIFT中作为参数传递的类型

从SwiftUI使用UIPageView时,同一页面连续显示两次的问题

Swift 扩展:通过方法重载增强现有类

如何在 Vapor 中制作可选的查询过滤器

在SwiftUI中如何预览嵌套的ScrollView,以避免触发可刷新修饰符

SwiftUI .task 视图修改器:运行在哪个线程中?

UIBezierPath() 和 DragGesture:连接点创建角而不是曲线

将每个枚举 case 与 Swift 中的一个类型相关联

使用 WrappingHStack 文本溢出到新行

(SwiftLint)如果有正文,如何编写规则(可能是自定义),在{之后总是\n(换行)?

如何以快速 Select 器菜单样式调整图像大小

如何仅将 SwiftUI 不透明度应用于父视图?

如何在 SwiftUI 中打开 ImagePicker?

UITableViewAlertForLayoutOutsideViewHierarchy 错误:仅警告一次(iOS 13 GM)

iOS 视图可见性消失了

Swift 中的单元测试致命错误

在这个例子中美元符号有什么作用?