我试图习惯于泛型(从未在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
}
我是否需要在这里某处进行类型转换(这会破坏目的,因为我需要向下转换为字符串或数组,添加代码并减少此函数的通用性)?
答案 0 :(得分:3)
如果你想返回第一个和最后一个元素,那么假设输入参数是某种类型的数组,它可能是安全的。
所以你可以这样实现你的功能
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自动确定了正确的类型。
在评论中,你说你想要一个字符串的第一个和最后一个字符。这里是代码,如果您使用上面的扩展
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
答案 1 :(得分:0)
如果我们谈论集合,那么让我们使用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是一种面向协议的语言。通常,您会发现自己扩展协议而不是扩展类或结构。