Swift中的泛型 [英] Generics in Swift

查看:106
本文介绍了Swift中的泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习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
}
对于第二个挑战,我在想的是一个通用函数,我可以传递一个集合(可以是一个数组,一个字典或一组集合) 。但对于 Set 类型,由于它没有定义的顺序,所以如何在 Set



谢谢。

解决方案

作为

 公共下标(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 be Equatable:

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 a Collection as well, it has an associated Index type and a subscript 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆