重载方法调用有替代方案:String.format

Overloaded method call has alternatives: String.format

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

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

overloaded method value format with alternatives: (x; java.util.Locale; x: String, X: Object*) (x:String,x: Object*) String cannot be applied to (*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 专家

我无法弄清楚到底是什么导致了 "overload clash" 但请注意下面的代码:

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

使用 StringOps 提供的方法。

String.format method in Java expects Objects as its arguments. The Object type in Java is equivalent to the AnyRef type in Scala. The primitive types in Scala extend AnyVal – not AnyRef. Read more about the differences between AnyVal, AnyRef, and Any in the docs or in this answer。最明显的修复是使用 Java 中的 Integer 包装器 class 来获得 Ints:

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

使用这些包装器 classes 几乎是单一 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