我正在学习 Swift 中的泛型。对我来说,这个话题很难理解。在我正在读的书中,关于泛型有两个挑战:
第一个挑战:它要求编写一个函数findAll(_:_:),该函数接受符合 Equatable 协议的任何类型 T 的数组和单个元素(也是 T 类型)。findAll(_:_:)应该返回一个整数数组,对应于数组中找到该元素的每个位置。例如,findAll([5,3,7,3,9], 3]应该返回[1,3].
第二个挑战:修改findAll(_:_:)为接受 Collection 而不是数组,并给出提示“您需要将返回类型从 [Int] 更改为 Collection 协议关联类型的数组”
这就是我为第一个挑战所做的
func findAll<T:Equatable> (_ first: [T], _ second: T) -> [Int] {
var array = [Int]()
for i in 0..<first.count {
if first[i] == second {
array.append(i)
}
}
return array
}
Run Code Online (Sandbox Code Playgroud)
对于第二个挑战,我正在考虑的是一个可以传递集合(可以是数组、字典或集合)的通用函数。但是对于Set类型,由于它没有定义的顺序,如何找到Set中项目的位置?
谢谢。
集合的下标方法定义为
public subscript(position: Self.Index) -> Self.Iterator.Element { get }
Run Code Online (Sandbox Code Playgroud)
这意味着你的函数应该作为参数
C,以及C.Iterator.Element并返回一个数组C.Index。此外,元素类型应该是Equatable:
func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable
{ ... }
Run Code Online (Sandbox Code Playgroud)
与数组的解决方案类似,可以循环遍历集合的索引:
func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable
{
var result: [C.Index] = []
var idx = collection.startIndex
while idx != collection.endIndex {
if collection[idx] == element {
result.append(idx)
}
collection.formIndex(after: &idx)
}
return result
}
Run Code Online (Sandbox Code Playgroud)
人们会期望像这样的东西
for idx in collection.startIndex ..< collection.endIndex
// or
for idx in collection.indices
Run Code Online (Sandbox Code Playgroud)
可行,但是(在 Swift 3 中)这需要对关联类型进行额外的约束Indices:
func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable, C.Indices.Iterator.Element == C.Index
{
var result: [C.Index] = []
for idx in collection.indices {
if collection[idx] == element {
result.append(idx)
}
}
return result
}
Run Code Online (Sandbox Code Playgroud)
这在 Swift 4 中不再是必需的,例如,请参阅 Unable to useindexs.contains() in a Collection extension in Swift 3以获得更好的解释。
现在可以使用以下方法来简化filter:
func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index]
where C.Iterator.Element: Equatable, C.Indices.Iterator.Element == C.Index
{
return collection.indices.filter { collection[$0] == element }
}
Run Code Online (Sandbox Code Playgroud)
示例( 的集合Character):
let chars = "abcdabcdabcd".characters
let indices = findAll(chars, "c")
for idx in indices {
print(chars[idx])
}
Run Code Online (Sandbox Code Playgroud)
Set也是a Collection,它有一个关联的Index
类型和一个subscript方法。例子:
let set = Set([1, 2, 3, 4, 5, 6, 7, 8, 9])
let indices = findAll(set, 3)
for idx in indices {
print(set[idx])
}
Run Code Online (Sandbox Code Playgroud)
最后,您可能希望将函数定义为类型
上的方法Collection:
extension Collection where Iterator.Element: Equatable, Indices.Iterator.Element == Index {
func allIndices(of element: Iterator.Element) -> [Index] {
return indices.filter { self[$0] == element }
}
}
// Example:
let indices = [1, 2, 3, 1, 2, 3].allIndices(of: 3)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2174 次 |
| 最近记录: |