我的问题在下面的代码中表达.我正在尝试获取一些具有.map功能的输入.我知道如果我调用.map,它会返回一个Int给我.
// In my case, they are different representations of Ints
// By that I mean that in the end it all boils down to Int
val list: Seq[Int] = Seq(1,2,3,4)
val optInt: Option[Int] = Some(1)
// I can use a .map with a Seq, check!
list.map {
value => println(value)
}
// I can use it with an Option, check!
optInt.map {
value => println(value)
}
// Well, you're asking yourself why do I have to do it,
// Why don't I use foreach to solve my problem. Check!
list.foreach(println)
optInt.foreach(println)
// The problem is that I don't know what I'm going to get as input
// The only thing I know is that it's "mappable" (it has the .map function)
// And that if I were to apply .map it would return Ints to me
// Like this:
def printValues(genericInputThatHasMap: ???) {
genericInputThatHasMap.map {
value => println(value)
}
}
// The point is, what do I have to do to have this functionality?
// I'm researching right now, but I still haven't found anything.
// That's why I'm asking it here =(
// this works:
def printValues(genericInputThatHasMap: Seq[Int]) {
genericInputThatHasMap.map {
value => println(value)
}
}
Run Code Online (Sandbox Code Playgroud)
提前致谢!干杯!
首先要快速了解map和foreach.如果您只对集合中每个项目执行带副作用的操作(例如,打印到标准输出或文件等)感兴趣,请使用foreach.如果您对通过转换旧元素中的每个元素来创建新集合感兴趣,请使用map.当你写作时xs.map(println),你实际上会打印出该集合的所有元素,但你也会得到一个(完全无用的)单元集合,并且还可能会混淆未来的代码读者 - 包括你自己 - 希望foreach是谁在这样的情况下使用.
现在问你的问题.你已经遇到了我认为Scala标准库最丑陋的事情之一 - 事实上,名为map和foreach(和flatMap)的方法在语言层面得到了与定义它们的特定类型无关的神奇处理.例如,我可以这样写:
case class Foo(n: Int) {
def foreach(f: Int => Unit) {
(0 until n) foreach f
}
}
Run Code Online (Sandbox Code Playgroud)
并在这样的for循环中使用它,因为我已经命名了我的方法foreach:
for (i <- Foo(10)) println(i)
Run Code Online (Sandbox Code Playgroud)
您可以使用结构类型在您自己的代码中执行类似的操作:
def printValues(xs: { def foreach(f: (Int) => Unit): Unit }) {
xs foreach println
}
Run Code Online (Sandbox Code Playgroud)
这里任何xs一个适当类型的foreach方法 - 例如a Option[Int]或List[Int]-will将按预期编译和工作.
当您尝试使用map或flatMap通过时,结构类型变得更加混乱,并且在其他方面不令人满意 - 例如,由于使用运行时反射,它们会产生一些丑陋的开销.它们实际上必须在Scala 2.10中明确启用,以避免出于这些原因发出警告.
作为塞尼亚的回答指出,Scalaz库提供了通过采用更为连贯的方法解决问题类型的类一样Monad.Monad但是,在这种情况下你不会想要使用它:它比你需要的更强大的抽象.你Each用来提供foreach,并Functor为map.例如,在Scalaz 7中:
import scalaz._, Scalaz._
def printValues[F[_]: Each](xs: F[Int]) = xs foreach println
Run Code Online (Sandbox Code Playgroud)
要么:
def incremented[F[_]: Functor](xs: F[Int]) = xs map (_ + 1)
Run Code Online (Sandbox Code Playgroud)
总而言之,您可以使用结构类型以标准的,惯用的,但可以说是丑陋的方式执行您想要的操作,或者您可以使用Scalaz来获得更清晰的解决方案,但代价是新的依赖项.