Swift中的泛型 [英] Generics in Swift
问题描述
我正在学习Swift中的泛型。对我而言,这个话题很难理解。在我正在阅读的书中,泛型有两个挑战:第一个挑战:它要求写一个函数 findAll(_:_:)
,它接受符合Equatable协议和单个元素(也是类型T)的任何类型T的数组和数组。 findAll(_:_:)
应该返回一个整数数组,对应于数组中找到该元素的每个位置。例如, findAll([5,3,7,3,9],3]
应返回 [1,3] $ c $第二项挑战:修改
findAll(_:_:)
接受一个Collection而不是一个数组,并给出一个提示你将需要将返回类型从[Int]更改为一个相关类型的Collection协议的数组。
func findAll< T:Equatable>(_ first:[T] ,_ second:T) - > [Int] {
对于第二个挑战,我在想的是一个通用函数,我可以传递一个集合(可以是一个数组,一个字典或一组集合) 。但对于 Set 类型,由于它没有定义的顺序,所以如何在 Set 强>?
var array = [Int]()
for i in 0 ..< first.count {
if first [i] == second {
array.append(i)
}
}
return array
}
谢谢。
解决方案作为
公共下标(position:Self.Index) - > Self.Iterator.Element {get}
这意味着你的函数应该作为参数
- 集合
C
和
- 值关联类型
C.Iterator.Element
并返回一个
C.Index
。另外,元素类型
应该是Equatable
:func findAll< C:Collection> (_ collection:C,_ element:C.Iterator.Element) - > [C.Index]
where C.Iterator.Element:Equatable
{...}
与您在数组中的解决方案类似,可以遍历
集合的索引:
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)
}
返回结果
}
在collection.startIndex中,对于idx而言,类似于
。< collection.endIndex
//或
为collection.indices中的idx
作品,但是(在Swift 3中)这需要在关联的
Indices
类型上额外约束
:func findAll< C:Collection> (_ collection:C,_ element:C.Iterator.Element) - > [C.Index]
其中C.Iterator.Element:Equatable,C.Indices.Iterator.Element == C.Index
{
var结果:[C.Index ] = []
为collection.indices中的idx {
如果集合[idx] ==元素{
result.append(idx)
}
}
返回结果
}
这不再是在Swift 4中是必需的,例如参见
无法在Swift 3中的集合扩展中使用indices.contains()作为一个很好的解释。
现在可以使用
filter
:func findAll< C:Collection> (_ collection:C,_ element:C.Iterator.Element) - > [C.Index]
其中C.Iterator.Element:Equatable,C.Indices.Iterator.Element == C.Index
{
return collection.indices.filter {collection [$ 0] ==元素}
}
示例(
字符的集合
):
let chars =abcdabcdabcd.characters
let indices = findAll chars,c)
在index {b $ b print(chars [idx])
}
Set 也是一个
集合
,它有一个关联的Index
类型和一个下标
方法。例如:
let set = Set([1,2,3,4,5,6,7,8,9] )
让indices = findAll(set,3)
在index {b $ b print(set [idx])
}
最后,您可能希望将函数定义为方法
在Collection
类型:
扩展集合其中Iterator.Element:Equatable,Indices.Iterator.Element == Index {
func allIndices(元素:Iterator.Element) - > [Index] {
return indices.filter {self [$ 0] == element}
}
}
//例子:
let indices = [1,2,3,1,2,3] .allIndices(of:3)
I am learning about Generics in Swift. For me, this topic is quite hard to understand. In the book I am reading, there is 2 challenges on Generics:
1st challenge: it asks to write a function
findAll(_:_:)
that takes and array of any type T that conforms to the Equatable protocol and a single element (also of type T).findAll(_:_:)
should return an array of integers corresponding to every location where the element was found in the array. For example,findAll([5,3,7,3,9], 3]
should return[1,3]
.2nd challenge: to modify
findAll(_:_:)
to accept a Collection instead of an array and it gives a hint "You will need to change the return type from [Int] to an array of an associated type of the Collection protocol"This is what i have done for first challenge
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 }
For the second challenge, what i am thinking about is a generic function that I can pass a Collection (can be an Array, a Dictionary or a Set). But for Set type, as it does not have a defined ordering, how do you find location of an item in a Set?
Thank you.
解决方案The subscript method of collections is defined as
public subscript(position: Self.Index) -> Self.Iterator.Element { get }
which means that your function should take as arguments
- a collection
C
, and- a value of the associated type
C.Iterator.Element
and return an array of
C.Index
. In addition, the element type should beEquatable
:func findAll<C: Collection> (_ collection: C, _ element: C.Iterator.Element) -> [C.Index] where C.Iterator.Element: Equatable { ... }
Similar as in your solution for arrays, one can loop over the collection's indices:
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 }
One would expect that something like
for idx in collection.startIndex ..< collection.endIndex // or for idx in collection.indices
works, but (in Swift 3) this requires an additional constraint on the associated
Indices
type: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 }
This is no longer necessary in Swift 4, see for example Unable to use indices.contains() in a Collection extension in Swift 3 for a good explanation.
This can now be simplified using
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 } }
Example (a collection of
Character
):let chars = "abcdabcdabcd".characters let indices = findAll(chars, "c") for idx in indices { print(chars[idx]) }
Set
is aCollection
as well, it has an associatedIndex
type and asubscript
method. Example:let set = Set([1, 2, 3, 4, 5, 6, 7, 8, 9]) let indices = findAll(set, 3) for idx in indices { print(set[idx]) }
Finally you might want to define the function as a method on the
Collection
type: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)
这篇关于Swift中的泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!