使用CanBuildFrom

时间:2015-10-31 09:46:43

标签: scala

现在我在scala 2.11.7中创建了CUI进度条对象,我正在模仿在F#,Console.showProgress中找到的那个,我发现它非常好。我尝试制作的进度条可以像:

一样使用
pregressBar ((1 to 100)) { i =>
  doSomeWork(i)
}

看起来像:

67% [================================>                 ]

我希望这个progressBar对象基于第一个参数序列做一些工作,并返回包含该工作结果的序列(这与map函数非常相似)。 而且我希望它像map函数一样,它输出的容器类需要与其输入的容器类相同。所以当输入是List时,输出也是List,当Array,输出是Array时.. 但就目前而言,我的实现只接受List类,即使我正在尝试使用CanBuildFrom。 这是代码:

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.language.higherKinds

object progressBar {

  def apply[A, B, S[A] <: Seq[A]](seq: S[A])(f: A => B)
   (implicit bf: CanBuildFrom[S[A], B, S[B]]): S[B] = {
    val result =
      for {i <- 0 until seq.size
         r = ((i.toDouble) / (seq.size.toDouble) * 100).toInt + 1
         _ = printf("%3d%% [%-50s]\r",r,"="*(r/2-1)+">")
         _ = System.out.flush
         v = f(seq(i))
      } yield v
    println
    result.to[S]
  }

  def main(args: Array[String]): Unit = {
    // test
    progressBar(List(1,2,3)) {_ =>
     Thread sleep 100
     0
    }
  }
}

例如,当我在主要部分中将List(1,2,3)更改为Array时,只会抛出类型不匹配错误。如何解决这个问题按预期工作? 我提前谢谢你。

1 个答案:

答案 0 :(得分:0)

由于"Expression: invalid null pointer" 不是Array,因此类型推断还有额外的工作要做。

一种解决方案是Seq的重载:

Array

此外,

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.language.higherKinds

import collection.mutable.WrappedArray
import reflect.ClassTag

object progressBar {

  def apply[A, B, S[A] <: Seq[A]](seq: S[A])(f: A => B)
   (implicit bf: CanBuildFrom[S[A], B, S[B]]): S[B] = {
    val result = seq.zipWithIndex map { case (v, i) =>
      val r = ((i.toDouble) / (seq.size.toDouble) * 100).toInt + 1
      printf("%3d%% [%-50s]\r",r,"="*(r/2-1)+">")
      System.out.flush
      f(v)
    }
    println
    result.to[S]
  }
  def apply[A, B : ClassTag](xs: Array[A])(f: A => B): Array[B] = {
    val w = apply(WrappedArray.make[A](xs))(f)
    w.array
  }
}

object Test extends App {

  // test
  progressBar(List(1,2,3)) { _ =>
    Thread sleep 1000
    0
  }
  progressBar.apply(Array(1,2,3)) { _ =>
    Thread sleep 1000
    0
  }
}

允许

object X {
  implicit class Bar[A, C[A] <: Seq[A]](private val vs: C[A]) {
    def progress[B](f: A => B)(implicit bf: CanBuildFrom[C[A], B, C[B]]): C[B] =
      progressBar(vs)(f)(bf)
  }
  implicit class ArrayBar[A](private val vs: Array[A]) {
    def progress[B: ClassTag](f: A => B): Array[B] =
      (WrappedArray.make[A](vs) progress f).array
  }
}