gpt4 book ai didi

ios - 下标的良好行为

转载 作者:行者123 更新时间:2023-11-29 01:04:22 25 4
gpt4 key购买 nike

我正在为 String 创建一个扩展,并且我正在尝试确定下标运算符的正确/预期/良好行为。目前,我有这个:

// Will crash on 0 length strings
subscript(kIndex: Int) -> Character {
var index = kIndex
index = index < 0 ? 0 : index
index = index >= self.length ? self.length-1 : index
let i = self.startIndex.advancedBy(index)
return self.characters[i]
}

这会导致字符串范围之外的所有值都被限制在字符串的边缘。虽然这减少了因将错误索引传递给下标而导致的崩溃,但感觉这不是正确的做法。如果索引超出范围,我无法从下标抛出异常并且不检查下标会导致 BAD_INSTRUCTION 错误。我能想到的唯一的其他选择是返回一个可选的,但这看起来很尴尬。权衡选项,我所拥有的似乎是最合理的,但我认为使用它的任何人都不会期望错误的索引返回有效结果。

所以,我的问题是:下标运算符的“标准”预期行为是什么?从可接受/适当的无效索引返回有效元素?谢谢。

最佳答案

如果您要在 String 上实现下标,您可能需要首先考虑为什么标准库选择不这样做。

当您调用self.startIndex.advancedBy(index)时,您实际上正在编写如下内容:

var i = self.startIndex
while i < index { i = i.successor() }

出现这种情况是因为 String.CharacterView.Index 不是随机访问索引类型。请参阅 advancedBy 上的文档.字符串索引不是随机访问的,因为字符串中的每个字符可能是字符串底层存储中的任意数量的字节 - 您不能仅通过跳转来获取字符n像使用 C 字符串一样将 n * characterSize 放入存储中。

因此,如果要使用下标运算符来迭代字符串中的字符:

for i in 0..<string.characters.count {
doSomethingWith(string[i])
}

...你会有一个看起来像在线性时间内运行的循环,因为它看起来就像一个数组迭代 - 每次通过循环都应该花费相同的时间,因为每个都只是递增 i 并使用恒定时间访问来获取 string[i],对吗?没有。第一次循环中的 advancedBy 调用调用 successor 一次,下一个调用它两次,依此类推...如果您的字符串有 n 个字符,最后一次通过循环调用 successor n 次(即使它生成的结果在上一次调用 时通过循环使用后继者 n-1 次)。换句话说,您刚刚完成了一个看起来像 O(n) 操作的 O(n2) 操作,为其他使用您的代码的人留下了性能成本炸弹。

这是完全支持 Unicode 的字符串库的价格。


无论如何,要回答您的实际问题 - 对于下标和域检查有两种思想流派:

  • 有一个可选的返回类型:func subscript(index: Index) -> Element?

    当客户端没有明智的方法来检查索引是否有效而不执行与查找相同的工作时,这就有意义了——例如对于字典,找出是否给定键的值与找出键的值是什么是一样的。

  • 要求索引有效,否则出现 fatal error 。

    通常的情况是 API 的客户端可以并且应该在访问下标之前检查有效性。这就是 Swift 数组所做的事情,因为数组知道它们的计数,并且您不需要查看数组来查看索引是否有效。

    对此的规范测试是前提条件:例如

    func subscript(index: Index) -> Element {
    precondition(isValid(index), "index must be valid")
    // ... do lookup ...
    }

    (这里,isValid 是特定于您的类的一些操作,用于验证索引——例如确保它 > 0 和 < count。)

在几乎任何用例中,在索引错误的情况下返回“真实”值并不是 Swift 惯用的做法,返回哨兵值也不合适——将带内值与哨兵分开是 Swift 的原因有选项。

其中哪一个更适合您的用例......好吧,由于您的用例存在问题,所以它有点洗。如果您 precondition 该索引 < count,您仍然会产生 O(n) 成本只是为了检查它(因为 String 必须检查其内容以找出哪些序列字节在知道它有多少个字符之前就构成了每个字符)。如果您将返回类型设为可选,并在调用 advancedBycount 后返回 nil,您仍然会产生 O(n) 成本。

关于ios - 下标的良好行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36581255/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com