【问题标题】:Swift: Chaining String/Substring methods yields 'ambiguous use of' errors. Fix or alternative?Swift:链接字符串/子字符串方法会产生“模糊使用”错误。修复还是替代?
【发布时间】:2017-10-08 16:33:48
【问题描述】:

我正在尝试使用 Swift 进行最基本的字符串操作。看起来 String 提供了我需要的一切,即使它依赖于 Substring 中间结果。所以这行得通

let myString = "0123456789"
let mySubstring = myString.dropFirst(2)
print(mySubstring.dropLast(2))

它成功生成“234567”作为子字符串。

但是,当我尝试链接调用时...

print(myString.dropFirst(2).dropLast(2))

我收到以下错误...

  9> print(myString.dropFirst(2).dropLast(2))
error: repl.swift:9:7: error: ambiguous use of 'dropFirst'
print(myString.dropFirst(2).dropLast(2))
      ^

Swift.Collection:39:17: note: found this candidate
    public func dropFirst(_ n: Int) -> Self.SubSequence
                ^

Swift.Sequence:20:17: note: found this candidate
    public func dropFirst(_ n: Int) -> AnySequence<Self.Element>
                ^

因此,编译器似乎在推断要调用哪个 dropFirst 方法时遇到了问题,这是可以理解的,因为它使用不同的返回类型定义了两次。

有没有办法解决这个问题?这只是 Apple 方面的糟糕 API 设计吗?我试图获得一个易于阅读和简洁的代码。我也可以通过使用 NSString 来使其工作,但这似乎很浪费,而且更加冗长和迟钝。

更新:

我可以通过在链后添加 as Substring 来获得更好的结果...

print(myString.dropFirst(2).dropLast(2) as Substring)

...因为这消除了重载方法的歧义。我仍然希望看到更简洁的解决方案。谢谢。

【问题讨论】:

  • 您在我的消息中看到错误输出了吗?它不适用于 Xcode 9 和 Swift 4。您使用的是哪个版本的 Xcode 和 Swift @vacawama?还是因为调用顺序?也许 dropLast 没有重载。
  • 有趣。谢谢。我读的时候错过了。 ;-)
  • this pull request 修复了这种歧义,您的代码在最新的开发快照中按预期编译。
  • 太棒了!谢谢。

标签: swift string nsstring substring ambiguous


【解决方案1】:

如果你定义了返回类型,那么解析使用哪个函数是没有问题的。有很多方法可以做到这一点,例如:

let mySubstring: Substring = myString.dropFirst(2).dropLast(2)

当然,正如你所说,你可以在表达式中插入这个 Substring 类型:

let mySubstring = (myString.dropFirst(2) as Substring).dropLast(2)

【讨论】:

  • 谢谢。似乎在链中的某处使用它或包含“作为子字符串”可以解决问题。事实上,只是将 as Substring 添加到链的最末端似乎可以消除更长的链的歧义。
  • 是的。我认为这种方式更简洁(我讨厌在表达式中插入句法噪音,除非我必须这样做),但是,就像我说的,有很多方法可以做到这一点。但是我在答案中添加了其他排列。
  • 或者只是初始化一个新字符串并对其应用 dropLast 。 String(myString.dropFirst(2)).dropLast(2)
  • 是的,我想过这个问题(Vadian 也正是这样建议的),但让我感到奇怪的是获得 Substring,将其转换为 String,然后获得 Substring String。您已经接受了中间 String 的(诚然,适度的)开销。如果你最后想要一个String,我会留在Substring,然后在最后进行字符串转换,例如String(myString.dropFirst(2).dropLast(2) as Substring).
  • 同意。我试图消除这里的开销。这是针对低延迟/高吞吐量情况下的一些内部循环代码。子字符串为此进行了优化。多次转换为字符串是不可能的。
【解决方案2】:

令人惊讶的是,如果您颠倒顺序并首先执行dropLast,它会起作用:

print(myString.dropLast(2).dropFirst(2))

【讨论】:

  • 这很有趣,因为 dropLast 没有被重载(只是查了一下)。不幸的是,这只是我正在使用的更长链的一个简短示例,因此仔细选择操作顺序并不总是有效。我想我只需要忍受它并根据需要消除歧义。
  • 不要害怕使用let 创建中间结果。任何值得一试的编译器都会对其进行优化,从而更容易调试正在发生的事情。
  • 是的,我明白这一点。我只是在寻找简洁。在我遇到这个问题的实际代码中,我不得不用 let 创建大约十几个中间结果。它只是让事情更难阅读和维护。我不必这样做是 Java、Python、C++、Scala、Ruby、C# 等...
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 2014-03-03
  • 2012-07-29
  • 1970-01-01
  • 2018-03-23
  • 2014-01-21
相关资源
最近更新 更多