swift - 如何约束函数参数的协议(protocol)关联类型

标签 swift swift-extensions

为了好玩,我尝试扩展 Dictionary 类来复制 Python 的 Counter 类。我正在尝试实现 init ,取CollectionType作为唯一的论点。然而,Swift 不允许这样做,因为 CollectionType的关联类型。所以,我尝试编写这样的代码:

import Foundation

// Must constrain extension with a protocol, not a class or struct
protocol SingletonIntProtocol { }
extension Int: SingletonIntProtocol { }

extension Dictionary where Value: SingletonIntProtocol { // i.e. Value == Int
    init(from sequence: SequenceType where sequence.Generator.Element == Key) {
        // Initialize
    }   
}

但是,Swift 不允许在参数列表中使用这种语法。有没有办法写init这样它就可以采用任何符合 CollectionType 的类型其值的类型为Key (泛型 Dictionary<Key: Hashable, Value> 中使用的类型名称)?最好我不会被迫写 init(from sequence: [Key]) ,这样我就可以采取任何 CollectionType (例如 CharacterView )。

最佳答案

您只是遇到了语法问题。你的基本想法看起来不错。正确的语法是:

init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {

这个答案的其余部分只是解释了为什么语法是这样的。如果第一部分让您满意,您实际上不需要阅读其余部分。

细微的差别在于,您尝试将 SequenceType where sequence.Generator.Element == Key 视为类型。它不是一种类型;而是一种类型。这是一个类型约束。正确的语法含义是:

There is a type Seq such that Seq.Generator.Element == Key, and sequence must be of that type.

虽然这看起来是同一件事,但不同之处在于 Seq 在任何给定时间都是一种特定类型。它不是“任何遵循此规则的类型”。它实际上是一种特定类型。每次您使用某种类型(例如 [Key])调用 init 时,Swift 都会创建一个全新的 init 方法,其中 Seq 替换为 [Key]。 (实际上,Swift 有时可以优化掉这个额外的方法,但原则上它是存在的。)这是理解泛型语法的关键点。

或者你可以只记住尖括号的位置,让编译器在你搞砸的时候提醒你,然后就到此为止了。大多数人在不学习支撑它的类型理论的情况下也能做得很好。

关于swift - 如何约束函数参数的协议(protocol)关联类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36320320/

相关文章:

ios - 没有初始化从初始化程序返回的所有存储属性时出错

swift - 委托(delegate)在 Swift 中的 2 个 UIView 之间进行通信

ios - 在 NavigationView 前面放置可交互的 View 隐藏导航栏

iphone - 为什么 “Use of undeclared type leftViewController” 发生在 Swift 中?

ios - 快速缩放 UIwebview

ios - 调用字符串扩展,包括从 Objective-C 用 Swift 编写的函数

ios - 为什么 swift 隐藏受限协议(protocol)的默认实现?

swift - 何时使用通用参数子句

ios - 如何在类型扩展方法中实例化类型?

swift - 在 Swift 中将整数转换为罗马数字字符串