快速泛型返回第一个和最后一个元素
Posted
技术标签:
【中文标题】快速泛型返回第一个和最后一个元素【英文标题】:swift generics return first and last element 【发布时间】:2016-05-18 20:14:07 【问题描述】:我正在尝试习惯泛型(从未在 objc 中使用它们)并想编写一个玩具函数,该函数接受任何类型的对象 () 并返回第一个和最后一个元素。假设,我只会在数组或字符串上使用它——我不断收到一个没有下标成员的错误。我完全理解错误消息告诉我 swift 不知道 T 可能包含一个确实有下标的类型 - 我只是想知道如何解决这个问题。
func firstAndLastFromCollection<T>(a:T?)
var count: Int = 0
for item in a as! [AnyObject]
count++
if count>1
var first = a?[0]
var last = a?[count-1]
return (first, last)
return something else here
我需要在这里的某个地方进行类型转换(这会破坏这里的目的,因为我需要向下转换为字符串或数组,添加代码并减少这个函数的通用性)?
【问题讨论】:
“接受任何类型的对象”——你不是说接受一个泛型类型的对象数组吗?在这种情况下,您需要让您的参数采用通用数组,即[T]
我希望能够传递一个字符串并提取第一个和最后一个字符。
【参考方案1】:
如果你想返回第一个和最后一个元素,那么假设输入参数是某种类型的数组可能是安全的。
所以你可以这样实现你的功能
func firstAndLast<T>(list:[T]) -> (first:T, last:T)?
guard let first = list.first, last = list.last else return nil
return (first, last)
该函数确实返回一个包含 2 个元素的元组,它们都具有相同类型的输入数组的通用元素。 返回的元组是一个选项,因为如果数组为空,则返回 nil。
示例
let nums = firstAndLast([1,2,3,4])
let words = firstAndLast(["One", "Two", "Three"])
您可以验证数组中泛型元素的类型变为元组内元素的类型。
在上面的例子中nums
被推断为(Int, Int)?
和words
(Words, Words)?
更多示例
let emptyList: [String] = []
firstAndLast(emptyList) // nil
扩展
最后你也可以把这段代码写成 Array 的扩展。
extension Array
var firstAndLast: (first:Element, last:Element)?
guard let first = self.first, last = self.last else return nil
return (first, last)
现在你可以写了
let aCoupleOfShows = ["Breaking Bad", "Better Call Saul", "Mr Robot"].firstAndLast
同样,如果您检查常量 aCoupleOfShows
的类型,您会看到它是 (first: String, last: String)?
。 Swift 确实自动推断出正确的类型。
最后一个例子
在 cmets 中你说你想要一个字符串的第一个和最后一个字符。如果你使用上面的扩展,这里是代码
if let chars = Array("Hello world".characters).firstAndLast
print("First char is \(chars.first), last char is \(chars.last) ")
//>> First char is H, last char is d
【讨论】:
【参考方案2】:如果我们在谈论集合,让我们使用CollectionType
:
func firstAndLastFromCollection<T: CollectionType>(a: T) -> (T.Generator.Element, T.Generator.Element)?
guard !a.isEmpty else
return nil
return (a.first!, a.lazy.reverse().first!)
print(firstAndLastFromCollection(["a", "b", "c"])) // ("a", "c")
print(firstAndLastFromCollection("abc".characters)) // ("a", "c")
print(firstAndLastFromCollection(0..<200)) // (0, 199)
print(firstAndLastFromCollection([] as [String])) // nil
如果您指定泛型类型也符合双向索引:
func firstAndLastFromCollection<T: CollectionType where T.Index : BidirectionalIndexType>(...) -> ...
那么你可以直接拨打last
:
return (a.first!, a.last!)
如果我们决定使用类别来实现它,我们根本不需要泛型:
extension CollectionType
func firstAndLast() -> (Generator.Element, Generator.Element)?
guard !self.isEmpty else
return nil
return (self.first!, self.lazy.reverse().first!)
extension CollectionType where Index: BidirectionalIndexType
func firstAndLast() -> (Generator.Element, Generator.Element)?
guard !self.isEmpty else
return nil
return (self.first!, self.last!)
print("abc".characters.firstAndLast())
Swift 是一种面向协议 的语言。通常你会发现自己扩展协议比扩展类或结构更多。
【讨论】:
非常感谢。刚刚从中学到了很多——去阅读有关生成器、守卫和惰性映射函数的信息。真的,谢谢你把我带到了兔子洞。以上是关于快速泛型返回第一个和最后一个元素的主要内容,如果未能解决你的问题,请参考以下文章
100个 Unity实用技能☀️ | C#泛型集合常用方法,查找符合要求的第一个元素并返回