scala中String和List之间的区别?

时间:2014-01-13 21:26:51

标签: string list scala types permutation

如果你做了Scala

scala> var st = "test"
st: java.lang.String = test

你得到一个java String。

但如果你这样做,你会得到一个Scala

scala> var st:String = "test2"
st: String = test2

问题:在Java字符串置换方法中,您只看到String类型,但在Scala中,您会看到List的示例(“a”,“b”,“c”)。有什么区别?

例如,在Java中,您可以对字符串排列执行此操作:

private static void permutation(String prefix, String str) {
    int n = str.length();
    //one-char string has only one permutation
    if (n == 1)
      System.out.println(prefix + str);
    else {
      //recursive case
      for (int i = 0; i < n; i++) {
        char ch = str.charAt(i);
        String rest = str.substring(0, i) + str.substring(i + 1);

        permutation(prefix + ch, rest);
  }
}

然而,在Scala中,它更多地是关于List:

def permutations[A](xs: List[A]) : List[List[A]] = xs match { 
  case Nil => List(Nil)
  case x::xs => permutations(xs).flatMap(inserts(x, _))
}
def inserts[A](x: A, ys: List[A]) : List[List[A]] = ys match {
  case Nil => List(List(x))
  case y::ys => (x::y::ys) :: inserts(x, ys).map(y::_)
}

1 个答案:

答案 0 :(得分:7)

没有Scala字符串

当您查看Predef.scala时,您会发现以下定义:

 type String        = java.lang.String

这意味着String只是java.lang.String的类型同义词。没有区别。

隐式转换

在Scala中有所谓的“pimp my library”模式(这个名称似乎在此期间已经改变,但这是原始名称)。此模式允许您向现有类型添加其他行为(不更改类型)。它是使用隐式转换实现的。这意味着在编译期间,编译器将在必要时注入一个将现有类型更改为新类型的函数。然后,这种新类型可以提供新的行为,通常是一些方便的方法。使用所谓的value classes时,此转换带有运行时成本。

Pimp my string:StringOps

Predef.scala为字符串提供了这种隐式转换:

@inline implicit def augmentString(x: String): StringOps = new StringOps(x)

此函数将类型为String的对象(即Java字符串)转换为类型为StringOps的对象。 StringOps提供了一些便利功能,特别是对于字符串(例如stripMargin)和一些使字符串行为像字符序列的函数(例如map)。

每当您在Java字符串上访问其中一个函数时,编译器将插入augmentString的函数调用,以将您的普通Java字符串转换为Scala StringOps。

为什么字符串是Chars序列?

Scala有一个非常强大的API,称为monadic API。此API允许您使用通用结构过滤,转换和组合许多不同类型。因此,您可以使用相同的API来访问,例如类型为List的对象以及类型为Future的对象。将此API也提供给字符串非常方便。

使用JSR 335,Java中也会有一个monadic API。但这需要一些时间,直到普通的Java stings也会获得开箱即用的monadic API。

性能方面的考虑:返回的方式很昂贵

虽然将字符串转换为字符序列没有运行时间成本,但相反的方式可能更昂贵。当你有一系列字符并希望它转换为字符串时,通常没有隐式转换。您必须使用mkString明确地执行此操作。

示例:

List('a','b','c').map(_.toUpper).mkString

StringOps有一些特殊的优化,即对于被视为字符序列的字符串。它们确实会自动转换回字符串。 StringOps中的方法在可能的情况下直接返回字符串作为结果,例如

def map[B](f: (A) ⇒ B): String[B] 
def filter(p: (Char) ⇒ Boolean): String 

对于这些函数,直接创建字符串通常与创建中间序列作为结果一样便宜。

当没有额外费用时,Scala会自动在字符序列和字符串之间进行转换。当成本很高时,您必须进行明确的转换。在所有常见用例中,您不必担心这一点,因为Scala会自动执行正确的操作。在所有其他情况下,知道幕后发生的事情可能是有用的。