我对OO编程和Swift有相当好的理解,然而,真正让我感到难过的一个领域是 Generators 和 Sequences (我很满意的概念顺便提一下协议。
例如,我从Swift Guide(Apple)
完成了这个练习“EXPERIMENT修改anyCommonElements函数,使函数返回任意两个序列共有的元素数组。”
转过来:
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
}
我对我编写的解决方案感到满意并且效果很好,包括Optional返回,但是我很遗憾为什么commonElements返回数组的类型需要这个< /强>:
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/
但我仍然完全迷失了 - 有人可以用简单的语言帮助解释这个问题,还是只是有点抽象而不容易描述?
真的很感激, 谢谢,约翰
答案 0 :(得分:12)
T是序列类型。为简单起见,让我们采用一个特殊而熟悉的案例,并说T是一个数组。
然后数组中包含的东西的类型是T.Generator.Element
。这是因为Array结构的定义方式。请记住,Array是泛型。它是一个SequenceType,它是一个具有空类型别名Generator的(通用)协议,它被约束为GeneratorType,而GeneratorType又是一个具有空类型别名Element的(通用)协议。当泛型是专用的时,那些空类型别名被填充&#34;与实际类型。所有序列都是这样的。因此,如果T是一个数组,则T.Generator.Element
表示&#34; 数组 元素&#34;
所以[T.Generator.Element]
表示&#34;与原始数组元素相同类型元素的数组。
您建议的表达式[T]
将意味着一组数组,这不是我们想要的。
好的,现在将T推广回任何序列(数组,字符串等),并且该解释继续有效。
答案 1 :(得分:3)
作者的答案不再适用于最新版本的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"])