Swift 中带有生成器和序列的泛型
Generics with Generators and Sequences in Swift
我对 OO 编程和 Swift 有相当好的理解,但是,真正让我感到困惑的一个领域是 Generators 和 Sequences(顺便说一句,我对协议的概念很好)。
例如,我从 Swift 指南 (Apple)
完成了这个练习
“实验修改 anyCommonElements 函数,使函数 return 成为任意两个序列共有的元素数组。”
转动这个:
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
进入这个:
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element]? {
var commonElements:[T.Generator.Element]? = nil
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
if (commonElements == nil)
{
commonElements = [] //init the array if not already
}
commonElements?.append(lhsItem) //add matching item to the array
}
}
}
return commonElements? //return nil or array of matched elements
}
我对我写的解决方案很满意,它运行良好,包括可选 return,但是我不知道为什么 commonElements return 数组的类型 需要这样:
var commonElements:[T.Generator.Element]
而不是这样:
var commonElements:[T]
我读过很多关于这个主题的文章,包括:
https://schani.wordpress.com/2014/06/06/generators-in-swift/
http://robots.thoughtbot.com/swift-sequences
http://natashatherobot.com/swift-conform-to-sequence-protocol/
但我还是一头雾水 - 谁能简单解释一下,还是有点抽象,不容易描述?
非常感谢,
谢谢,约翰
Swift5 的更新:
(使用 Sequence
而不是 SequenceType
,Iterator
而不是 Generator
,以及新的 Where
语法。
func anyCommonElements <T, U> (lhs: T, rhs: U) -> [T.Iterator.Element] where T: Sequence, U: Sequence, T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var commonElements:[T.Iterator.Element] = []
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
commonElements.append(lhsItem) //add matching item to the array
}
}
}
return commonElements //return nil or array of matched elements
}
事实上,您现在可以只做 T.Element
,而忽略迭代器。
T是序列类型。为简单起见,让我们以一个特殊且熟悉的情况为例,假设 T 是一个数组。
那么数组中包含的东西的类型就是T.Generator.Element
。这是因为 Array 结构的定义方式。请记住,Array 是一个 generic。它是一个 SequenceType,它是一个具有空类型别名 Generator 的(通用)协议,它被限制为一个 GeneratorType,而后者又是一个具有空类型别名 Element 的(通用)协议。当泛型被专门化时,那些空类型别名是 "filled in" 具有实际类型。所有的序列都是这样。所以如果 T 是一个数组,那么 T.Generator.Element
意味着 "the actual type of this array's actual elements".
所以[T.Generator.Element]
表示“与原始数组的元素具有相同类型元素的数组。
您建议的表达式 [T]
将表示 数组 的数组,这不是我们想要的。
好的,现在将 T 概括为任何序列(数组、字符串等),并且该解释继续有效。
作者的回答对Swift的最新版本不再有效。这是与版本 3.0.1 兼容的更新,它们简化了如何制作通用数组。 注意:我最初使用的是 [Any] 数组,但根据下面的反馈更新了代码。
func showCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var result:[T.Iterator.Element] = []
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
result.append(lhsItem)
}
}
}
return result
}
您可以使用以下命令测试代码:
showCommonElements([1, 2, 3, 4, 5], [4, 7, 3])
showCommonElements(["apple", "banana", "orange", "peach"], ["orange", "pear", "apple"])
我对 OO 编程和 Swift 有相当好的理解,但是,真正让我感到困惑的一个领域是 Generators 和 Sequences(顺便说一句,我对协议的概念很好)。
例如,我从 Swift 指南 (Apple)
完成了这个练习“实验修改 anyCommonElements 函数,使函数 return 成为任意两个序列共有的元素数组。”
转动这个:
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
进入这个:
func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element]? {
var commonElements:[T.Generator.Element]? = nil
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
if (commonElements == nil)
{
commonElements = [] //init the array if not already
}
commonElements?.append(lhsItem) //add matching item to the array
}
}
}
return commonElements? //return nil or array of matched elements
}
我对我写的解决方案很满意,它运行良好,包括可选 return,但是我不知道为什么 commonElements return 数组的类型 需要这样:
var commonElements:[T.Generator.Element]
而不是这样:
var commonElements:[T]
我读过很多关于这个主题的文章,包括:
https://schani.wordpress.com/2014/06/06/generators-in-swift/
http://robots.thoughtbot.com/swift-sequences
http://natashatherobot.com/swift-conform-to-sequence-protocol/
但我还是一头雾水 - 谁能简单解释一下,还是有点抽象,不容易描述?
非常感谢, 谢谢,约翰
Swift5 的更新:
(使用 Sequence
而不是 SequenceType
,Iterator
而不是 Generator
,以及新的 Where
语法。
func anyCommonElements <T, U> (lhs: T, rhs: U) -> [T.Iterator.Element] where T: Sequence, U: Sequence, T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var commonElements:[T.Iterator.Element] = []
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
commonElements.append(lhsItem) //add matching item to the array
}
}
}
return commonElements //return nil or array of matched elements
}
事实上,您现在可以只做 T.Element
,而忽略迭代器。
T是序列类型。为简单起见,让我们以一个特殊且熟悉的情况为例,假设 T 是一个数组。
那么数组中包含的东西的类型就是T.Generator.Element
。这是因为 Array 结构的定义方式。请记住,Array 是一个 generic。它是一个 SequenceType,它是一个具有空类型别名 Generator 的(通用)协议,它被限制为一个 GeneratorType,而后者又是一个具有空类型别名 Element 的(通用)协议。当泛型被专门化时,那些空类型别名是 "filled in" 具有实际类型。所有的序列都是这样。所以如果 T 是一个数组,那么 T.Generator.Element
意味着 "the actual type of this array's actual elements".
所以[T.Generator.Element]
表示“与原始数组的元素具有相同类型元素的数组。
您建议的表达式 [T]
将表示 数组 的数组,这不是我们想要的。
好的,现在将 T 概括为任何序列(数组、字符串等),并且该解释继续有效。
作者的回答对Swift的最新版本不再有效。这是与版本 3.0.1 兼容的更新,它们简化了如何制作通用数组。 注意:我最初使用的是 [Any] 数组,但根据下面的反馈更新了代码。
func showCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var result:[T.Iterator.Element] = []
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
result.append(lhsItem)
}
}
}
return result
}
您可以使用以下命令测试代码:
showCommonElements([1, 2, 3, 4, 5], [4, 7, 3])
showCommonElements(["apple", "banana", "orange", "peach"], ["orange", "pear", "apple"])