【问题标题】:How to return a generic collection or iterator in Swift?如何在 Swift 中返回泛型集合或迭代器?
【发布时间】:2022-01-24 13:15:50
【问题描述】:

我正在尝试做这样的事情:

func fullOrSubarray(array: [Int]) -> ReturnType {
    return array.count < 10 ? array : array[0..<10]
}

当我试图返回Array&lt;Int&gt;ArraySlice&lt;Int&gt; 时,我应该写什么到ReturnType

我知道我可以简单地将ArraySlice&lt;Int&gt; 转换为Array&lt;Int&gt;(反之亦然),但出于性能原因我不想这样做。我想返回一些通用集合或迭代器类型,但 Swift 似乎没有。我是否必须为这样的事情编写自定义迭代器?其他语言有各种通用迭代器,所以我可以互换返回 Array、Set 等。

【问题讨论】:

  • 将 Array 转换为 ArraySlice 的性能问题是什么?那应该几乎是免费的。
  • 另外,你可能想看看 stdlib 是如何做这种事情的。例如,您在这里写的正是prefix。我知道你也可能在做其他事情,但是看看prefix 是如何实现的,你应该了解如何做好这件事:github.com/apple/swift/blob/main/stdlib/public/core/…
  • 要将集合转换为子序列(Array -> ArraySlice),您可以使用UnboundedRange operator array[...] 这会将完整数组作为数组切片返回

标签: arrays swift collections iterator


【解决方案1】:

可以按照您的描述进行操作,但首先,您应该看看是否可以避免它。您给出的具体示例正是prefix,绝对应该实现为:

func fullOrSubarray(array: [Int]) -> ArraySlice<Int> {
    array.prefix(10)
}

此处返回的正确内容是 ArraySlice。没有理由退回其他东西。看看implementation of prefix,看看 stdlib 是如何处理这个问题的。

也就是说,在极少数情况下,执行您所描述的操作可能会很有用。例如,底层数据可能位于 Set 或 Array 中,您希望避免复制。在这种情况下,正确的工具是 AnySequence 或 AnyCollection:

func fullOrSubarray(array: [Int]) -> AnySequence<Int> {
    array.count < 10 ? AnySequence(array) : AnySequence(array[0..<10])
}

但这是一种非常不寻常的情况,永远不会用于 Array 和 ArraySlice。为此,只需使用 ArraySlice,或转换回 Array。不要假设从切片转换为数组的成本很高。 stdlib 对于内部写时复制数组缓冲区非常聪明,并且通常可以避免制作任何副本。

即使数据当前可能是一个集合,除非它非常大或经常访问,否则通常最好在返回之前将其转换为数组。如果它经常作为一个数组访问,我倾向于将它存储为一个数组而不是一个集合。

但如果所有这些都失败了,并且您需要返回未知的序列类型,这就是 AnySequence(或 AnyCollection)的用途。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    相关资源
    最近更新 更多