【问题标题】:Overloaded method call has alternatives: String.format重载方法调用有替代方案:String.format
【发布时间】:2015-07-05 02:55:49
【问题描述】:

我在下面编写了以下 Scala 代码来处理我传入的字符串,格式化字符串,将其附加到 StringBuilder 并将带有转义 unicode 的格式化 String 返回给我的调用者以进行其他处理。

Scala 编译器在 String.format 调用的行中抱怨以下错误:

带有替代方法的重载方法值格式:(x$1; java.util.Locale; x$2: String, X$3: Object*)(x$1:String,x$2: Object*) 字符串不能应用于(*String, Int)

class TestClass {    
    private def escapeUnicodeStuff(input: String): String = {
            //type StringBuilder = scala.collection.mutable.StringBuilder
            val sb = new StringBuilder()
            val cPtArray = toCodePointArray(input) //this method call returns an Array[Int]
            val len = cPtArray.length
            for (i <- 0 until len) {
              if (cPtArray(i) > 65535) {
                val hi = (cPtArray(i) - 0x10000) / 0x400 + 0xD800
                val lo = (cPtArray(i) - 0x10000) % 0x400 + 0xDC00
                sb.append(String.format("\\u%04x\\u%04x", hi, lo)) //**complains here**
              } else if (codePointArray(i) > 127) {
                sb.append(String.format("\\u%04x", codePointArray(i))) //**complains here**
              } else {
                sb.append(String.format("%c", codePointArray(i))) //**complains here**
              }
            }
            sb.toString
          }

    }

我该如何解决这个问题?如何清理代码以实现格式化字符串的目的?在此先感谢 Scala 专家

【问题讨论】:

  • 再次感谢您的编辑。这个问题看起来好多了。

标签: string scala unicode stringbuilder


【解决方案1】:

我无法弄清楚究竟是什么导致了“过载冲突”,但请注意下面的代码:

scala> "\\u%04x\\u%04x".format(10,20)
res12: String = \u000a\u0014

使用StringOps提供的那个就可以了。

【讨论】:

  • 你的意思是StringOps提供的方法吗?
【解决方案2】:

Java 中的String.format 方法需要Objects 作为其参数。 Java 中的 Object 类型等价于 Scala 中的 AnyRef 类型。 Scala 中的原始类型扩展了AnyVal——而不是AnyRef。阅读更多关于AnyValAnyRefAny in the docsthis answer 之间的区别。最明显的解决方法是使用 Java 中的 Integer 包装类来获得 Object 表示 Ints

String.format("\\u%04x\\u%04x", new Integer(hi), new Integer(lo))

使用这些包装类几乎是 Scala 代码的象征,只有在没有更好的选择时才应该用于与 Java 的互操作性。在 Scala 中更自然的方法是使用 StringOps 等效方法 format

"\\u%04x\\u%04x".format(hi, lo)

您还可以使用f interpolator 以获得更简洁的语法:

f"\\u$hi%04x\\u$lo%04x"

此外,像您在此处使用的 for 循环在 Scala 中是统一的。最好使用mapfoldLeft 甚至foreach 之类的函数列表方法之一以及使用match 语法的部分函数。例如,您可以尝试以下操作:

toCodePointArray(input).foreach {
    case x if x > 65535 => 
        val hi = (x - 0x10000) / 0x400 + 0xD800
        val lo = (x - 0x10000) % 0x400 + 0xDC00
        sb.append(f"\\u$hi%04x\\u$lo%04x") 
    case x if > 127 => sb.append(f"\\u$x%04x") 
    case x => sb.append(f"$x%c")    
}

或者,如果您不必使用StringBuilder(实际上只需要在附加许多字符串的情况下使用),您可以将整个方法体替换为foldLeft

def escapeUnicodeStuff(input: String) = toCodePointArray(input).foldLeft("") {
    case (acc, x) if x > 65535 => 
        val hi = (x - 0x10000) / 0x400 + 0xD800
        val lo = (x - 0x10000) % 0x400 + 0xDC00
        acc + f"\\u$hi%04x\\u$lo%04x"
    case (acc, x) if x > 127 => acc + f"\\u$x%04x"
    case (acc, x) => acc + f"$x%c"
}

或者一个偶数map,后跟一个mkString

def escapeUnicodeStuff(input: String) = toCodePointArray(input).map {
    case x if x > 65535 => 
        val hi = (x - 0x10000) / 0x400 + 0xD800
        val lo = (x - 0x10000) % 0x400 + 0xDC00
        f"\\u$hi%04x\\u$lo%04x"
    case x if x > 127 => f"\\u$x%04x"
    case x => f"$x%c"
}.mkString

【讨论】:

  • 感谢您花这么多时间和精力来回答。我喜欢你的解释非常清晰和翔实。我喜欢这种非常优雅的案例方法。
  • 使用第二种解决方案,编译器说:类型不匹配:所需单位:字符串
  • 我做对了。您的代码非常完美。我只是没有看到正确的东西。谢谢
  • 你是真正的救星
猜你喜欢
  • 1970-01-01
  • 2021-09-12
  • 2019-04-22
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多