了解Scala中的字符串和map方法

St.*_*rio 4 string dictionary scala

我编写了以下简单示例来了解map方法的工作原理:

object Main{
  def main (args : Array[String]) = {
    val test = "abc"
    val t = Vector(97, 98, 99)
    println(test.map(c => (c + 1)))               //1 Vector(98, 99, 100)
    println(test.map(c => (c + 1).toChar))        //2 bcd
    println(t.map(i => (i + 1)))                  //3 Vector(98, 99, 100)
    println(t.map(i => (i + 1).toChar))           //4 Vector(b, c, d)
  };
}
Run Code Online (Sandbox Code Playgroud)

我不太明白为什么要打印bcd //2.因为每个String都被Scala视为Seq我认为test.map(c => (c + 1).toChar)应该生成另一个Seq.如//1建议Vector(b, c, d).但正如你所看到的,它没有.为什么?它是如何实际工作的?

Has*_*tor 7

这是Scala集合的一个特性(在这种情况下,String被视为字符集合).真正的解释是相当复杂的,涉及对类型类的理解(我猜,这就是为什么在评论中提到了Haskell),但简单的解释是,并不是很难.

关键是,Scala集合库作者非常努力地避免代码重复.例如,map函数on String实际上是在这里定义的:scala.collection.TraversableLike#map.另一方面,这种任务的天真方法会使得map返回TraversableLike,而不是map被调用的原始类型(它就是String).这就是为什么他们想出了一种方法,可以避免代码重复和不必要的类型转换或太一般的返回类型.

基本上,Scala集合方法map生成的类型尽可能接近它所调用的类型.这是使用一个名为的类型类来实现的CanBuildFrom.map外观的完整签名如下:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Run Code Online (Sandbox Code Playgroud)

什么是类型类和CanBuildFrom周围有很多解释.我建议先在这里查看:http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html#factoring-out-common-operations.另一个很好的解释是:Scala 2.8 CanBuildFrom

  • +1真正简短的回答是Scala的集合操作类似于Smalltalk的类型保留,而不是大多数类型 - 总是类似Java,.NET(`IEnumerable`)或Ruby(`Array`). (2认同)