使用自定义CanBuildFrom和Builder获取映射函数以在Scala中工作

使用自定义CanBuildFrom和Builder获取映射函数以在Scala中工作,scala,map,Scala,Map,我让一个生成器用Int生成一个字符串: class MyBuilder extends LazyBuilder[Int, String] { def result: String = "value: " + Int.toString } 这可以通过实施来实现: class IntToStringCanBuildFrom extends CanBuildFrom[Set[Int], Int, String] { def apply(from: Set[Int]

我让一个生成器用Int生成一个字符串:

  class MyBuilder extends LazyBuilder[Int, String]
  {
    def result: String = "value: " + Int.toString
  }
这可以通过实施来实现:

  class IntToStringCanBuildFrom extends CanBuildFrom[Set[Int], Int, String]
  {
    def apply(from: Set[Int]) = this.apply()
    def apply() : MyBuilder = new MyBuilder
  }
我想在下面的例子中使用它:

val list = List(1, 2, 3)
val result = list.map(2*)(new IntToStringCanBuildFrom)
但我得到一个编译错误:

- type mismatch; found : Test.IntToStringCanBuildFrom required: 
 scala.collection.generic.CanBuildFrom[List[Int],Int,?]

我到底做错了什么?如何做到这一点?显然,它不喜欢我的CanBuildFrom实现有一个字符串类型的param,但我认为这应该是实现这一点的方法。

要做到这一点,代码中有几点需要更改:

  • 首先,您可以将
    CanBuildFrom
    定义为用于
    将[Int]
    设置为输入,但您给它一个
    列表[Int]
    (它不是
    !)。因此,它应该是,例如,
    CanBuildFrom[Seq[Int],Int,String]
    。因为
    列表
    是一个
    序列
    ,所以它可以工作

  • 然后,您的懒惰构建器需要对它接收到的元素进行实际操作。它公开了一个
    受保护的var parts:ListBuffer[TraversableOnce[Int]]
    ,其中包含添加到其中的所有内容。让我们只打印它的内容:

    class MyBuilder extends LazyBuilder[Int, String] {
      def result: String = "value: " + parts.flatten.mkString(",")
    }
    
    然后,调用时,
    CanBuildFrom
    可以创建该生成器:

    class IntSeqToStringCanBuildFrom extends CanBuildFrom[Seq[Int], Int, String] {
      def apply(from: Seq[Int]): Builder[Int, String] = apply()
      def apply(): Builder[Int, String] = new MyBuilder
    }
    
  • 最后,您可以直接使用它:

    scala> val list = List(1, 2, 3)
    list: List[Int] = List(1, 2, 3)
    
    scala> val result = list.map(2 * _)(new IntSeqToStringCanBuildFrom)
    result: String = value: 2,4,6
    
    或通过隐式范围间接:

    scala> implicit val intSeqCanBuildFrom = new IntSeqToStringCanBuildFrom
    intSeqCanBuildFrom: IntSeqToStringCanBuildFrom = IntSeqToStringCanBuildFrom@52cc537d
    
    scala> val result: String = list.map(2 * _)
    result: String = value: 2,4,6
    

谢谢!我不确定我怎么会错过这是一个集合而不是序列或列表。然而,您的结果将字符串显示为单个项,但我想将每个Int转换为字符串,因此在本例中创建“value:2”、“value:4”和“value:6”。我该怎么做呢?我不确定我是否能满足您的要求:您希望每个
Int
都有一个
String
,因此您希望,例如,一个
Seq[String]
作为输出?但是,
list.map(s=>”值:“+s)
就足够了,不需要
CanBuildFrom
。你想用你的
CanBuildFrom
生成什么样的集合类型?是的,我知道这不是一个很好的例子,这不是一个真实的情况,我只是想了解这个问题。我最初认为它的工作方式是为每个元素调用构建器,但正如您所说,它将获得整个parts ListBuffer,我必须从中生成我自己的Seq。现在我有了一个
类MyBuilder extensed LazyBuilder[Int,Seq[String]]
和一个
类IntToStringCanBuildFrom extensed CanBuildFrom[Seq[Int],Int,Seq[String]]
,这似乎满足了我的需求。