0

我正在尝试习惯泛型(从未在 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
 }

我需要在这里的某个地方进行类型转换(这会破坏这里的目的,因为我需要向下转换为字符串或数组,添加代码并减少这个函数的通用性)?

4

2 回答 2

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 
于 2016-05-18T20:32:49.223 回答
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 是一种面向协议的语言。通常你会发现自己扩展协议比扩展类或结构更多。

于 2016-05-18T20:40:25.283 回答