【问题标题】:Understanding String in Scala and the map method理解 Scala 中的 String 和 map 方法
【发布时间】:2016-06-23 15:04:20
【问题描述】:

我写了下面这个简单的例子来理解 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)
  };
}

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

【问题讨论】:

  • 虽然它是用 Haskell 编写的,但它是我在 Scala 中学习 FP 的方式 - learnyouahaskell.com/…。我建议购买和阅读manning.com/books/functional-programming-in-scala。或者,我建议learnyouahaskell.com,它是在线免费的。
  • @KevinMeredith 您是否认真假设需要学习 Haskell 才能了解 Scala 字符串的工作原理?
  • 出于这个原因,我将其作为评论而不是答案发布。要了解map,我的观点和经验是,首先了解函数式编程的基础知识是值得的——因为map 是FP 的基础。
  • @KevinMeredith ...特别是解释 Scala 的 CanBuildFrom,它在 Haskell 中根本不存在?
  • @VictorMoroz - 我发现Programming in Scala, 3rd edition 的第 25 章(Scala 集合的架构)对CanBuildFrom 给出了很好的解释。还有 - 好点,维克多,关于CanBuildFrom 的问题。我应该阅读这个问题,而不是假设它是关于理解 FP 中的map

标签: string scala dictionary


【解决方案1】:

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

关键是,Scala 集合库的作者非常努力地避免代码重复。比如String上的map函数其实就是在这里定义的:scala.collection.TraversableLike#map。另一方面,对此类任务的幼稚方法会使map 返回TraversableLike,而不是调用map 的原始类型(它是String)。这就是为什么他们提出了一种方法,可以避免代码重复和不必要的类型转换或过于笼统的返回类型。

基本上,像map 这样的Scala 集合方法产生的类型尽可能接近它被调用的类型。这是使用名为CanBuildFrom 的类型类实现的。 map 的完整签名如下所示:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

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

【讨论】:

  • 这样的例子是,即使测试被声明为 Seq[Char] 它仍然被转换为字符串
  • +1 真正简短的答案是 Scala 的集合操作像 Smalltalk 那样保持类型,而不是像 Java、.NET (IEnumerable) 或 Ruby (Array )。
【解决方案2】:

当您使用地图时,会发生这种情况:[List|Seq|etc].map([eachElement] => [do something])

map 对左侧变量的每个元素应用一些操作:"abc".map(letter => letter + 1) 将为String "abc" 的每个元素加 1。并且Stringabc 的每个元素在此处被称为“字母”(其类型为Char

"abc" 是一个字符串,和在 C++ 中一样,它被视为一个字符数组。但是由于test 是String 类型,所以map 函数也给出了一个String。

我尝试了以下方法:

val test2 : Seq[Char] = "abc"

但我仍然得到 String 类型的结果,我猜 Scala 会自动从 Seq[Char] 转换为 String

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多