例如,假设我们讨论的是Int类型的元素(但问题仍然适用于任何类型)
我有一些功能需要循环一系列Ints . 但我不在乎幕后这个序列是作为一个数组,或一个Set或任何其他奇特的结构实现,唯一的要求是我们可以循环它们 .
Swift标准库将协议SequenceType定义为“可以使用for ... in循环迭代的类型” . 所以我的直觉是定义这样的协议:
protocol HasSequenceOfInts {
var seq : SequenceType<Int> { get }
}
但这并不是一个协议 . 任何特定的SequenceType都具有特定类型的元素,但它仅作为关联类型提供:SequenceType.Generator.Element
所以问题是:
How can we define a protocol which requires a specific type of sequence?
这是我尝试过的其他一些事情,以及为什么他们不对:
Fail 1
protocol HasSequenceOfInts {
var seq : SequenceType { get }
}
协议'SequenceType'只能用作通用约束,因为它具有Self或相关类型要求
Fail 2
protocol HasSequenceOfInts {
var seq : AnySequence<Int> { get }
}
class ArrayOfInts : HasSequenceOfInts {
var seq : [Int] = [0,1,2]
}
我认为这个可行,但是当我尝试使用数组的具体实现时,我们得到了
类型'ArrayOfInts'不符合协议'HasSequenceOfInts'
这是因为Array不是AnySequence(令我惊讶的是......我的期望是AnySequence会匹配任何Ints序列)
Fail 3
protocol HasSequenceOfInts {
typealias S : SequenceType
var seq : S { get }
}
编译,但序列seq的元素没有义务类型为Int
Fail 4
protocol HasSequenceOfInts {
var seq : SequenceType where S.Generator.Element == Int
}
不能在那里使用where子句
所以现在我完全没有想法 . 我可以很容易地让我的协议需要一个Int of Array,但后来我没有充分的理由限制实现,这感觉非常迅速 .
Update Success
请参阅@ rob-napier的回答,它解释得非常好 . 我的失败2非常接近 . 使用AnySequence可以工作,但是在你的符合要求的类中,你需要确保从你正在使用的任何类型的序列转换为AnySequence . 例如:
protocol HasSequenceOfInts {
var seq : AnySequence<Int> { get }
}
class ArrayOfInts : HasSequenceOfInts {
var _seq : [Int] = [0,1,2]
var seq : AnySequence<Int> {
get {
return AnySequence(self._seq)
}
}
}
4 回答
这是Daniel Howard要求的非常具体的例子
1)符合SequenceType协议的类型几乎可以是任何序列,即使Array或Set都符合SequenceType协议,它们的大多数功能来自CollectionType上的继承(符合SequenceType)
丹尼尔,在你的游乐场试试这个简单的例子
如您所见,它符合SequenceType协议并产生无限的Int数据流 . 在你尝试实施某些事情之前,你必须回答几个问题
可以重用一些在标准Swift库中可用的功能'for free'吗?
我试图模仿一些Swift不支持的功能? Swift不是C,Swift不是ObjectiveC ......我们在Swift之前使用的很多构造在Swift中都没有 .
以我们能够理解您的要求的方式定义您的问题
你在找这样的东西吗?
我相信你需要将它的要求降低到只有Int并用泛型来解决它:
在Swift目前的状态下,你可能无法做到你想要的,也许在未来 .
这个问题有两个方面:
接受任意顺序的整数
返回或存储任意序列的整数
在第一种情况下,答案是使用泛型 . 例如:
在第二种情况下,您需要一个类型橡皮擦 . 类型擦除器是一种包装器,它隐藏了某些底层实现的实际类型,并仅提供了接口 . Swift在stdlib中有几个,大多以
Any
为前缀 . 在这种情况下,你想要AnySequence
.有关
AnySequence
和类型擦除器的更多信息,请参阅A Little Respect for AnySequence .如果你需要协议形式(通常你不需要;你只需要在_356207中使用泛型),类型橡皮擦也是那里的工具:
但
seq
必须返回AnySequence<Int>
. 它无法返回[Int]
.你可以采用更深层次的一层,但有时它会产生比它解决的更多麻烦 . 你可以定义:
但现在
HasSequenceOfInts
有一个typealias
,其中包含所有限制 .SeqInt
可以是任何类型的IntegerType
(不仅仅是Int
),所以看起来就像一个受约束的SequenceType
,并且通常需要它自己的类型橡皮擦 . 所以偶尔这种技术很有用,但在你的具体情况下它只能让你基本上回到你开始的地方 . 你不能在这里约束SeqInt
到Int
. 它必须是一个协议(当然你可以发明一个协议,使Int
成为唯一符合标准的类型,但这并没有太大变化) .顺便说一句,关于类型擦除器,你可能会看到它们只是一个转发给其他东西的盒子 . 这表明将来编译器将能够为我们自动生成这些类型擦除器 . 编译器已经为我们修复了其他拳击问题 . 例如,您以前必须创建一个
Box
类用于保存具有通用关联值的枚举 . 现在用indirect
半自动完成 . 我们可以想象一个类似的机制被添加到自动创建AnySequence
时's required by the compiler. So I don'认为这是一个很深的"Swift's design doesn't allow it."我认为它只是"the Swift compiler doesn't handle it yet."(在Swift 4中测试和工作,which introduces the associatedtype constraints needed for this)
声明您的原始协议,事情将符合:
现在,你可以写
就像你一直想要的那样
但是,如果您尝试创建
[HasSequenceOfInts]
类型的数组,或将其分配给变量(或基本上对其执行任何操作),您将收到错误消息有趣的来了 .
我们将创建另一个协议
HasSequenceOfInts_
(随意选择更具描述性的名称) which will not have associated type requirements, and will automatically be conformed to by HasSequenceOfInts :请注意,您永远不需要显式符合
HasSequenceOfInts_
,因为HasSequenceOfInts
已经符合它,并且您可以从扩展中免费获得完整的实现 .现在,如果您需要创建一个数组或将符合此协议的内容的实例分配给变量,请使用
HasSequenceOfInts_
作为类型而不是HasSequenceOfInts
,并访问seq_
属性( note: ,因为允许函数重载,如果您创建了一个函数seq()
而不是实例变量,你可以给它相同的名称,它会工作):这需要比接受的答案多一些设置,但这意味着您不必记住在实现协议的每种类型中将返回值包装在
AnySequence(...)
中 .