scala> val shares = Map("Apple" -> 23, "MicroSoft" -> 50, "IBM" -> 17)
shares: scala.collection.immutable.Map[java.lang.String,Int]
= Map(Apple -> 23, MicroSoft -> 50, IBM -> 17)
scala> val shareholders = shares map {_._1}
shareholders: scala.collection.immutable.Iterable[java.lang.String]
= List(Apple, MicroSoft, IBM)
scala> val newShares = shares map {case(k, v) => (k, 1.5 * v)}
newShares: scala.collection.immutable.Map[java.lang.String,Double]
= Map(Apple -> 34.5, MicroSoft -> 75.0, IBM -> 25.5)
从这个例子看,map
方法似乎在返回类型上重载。在返回类型上重载是不可能的?有人可以解释一下这里发生了什么吗?
答案 0 :(得分:12)
map
没有重载。相反,有一种方法具有抽象返回类型。
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
在字节码中,它被删除为Object
:
public abstract java.lang.Object map(scala.Function1, scala.collection.generic.CanBuildFrom);
中有最佳描述
答案 1 :(得分:5)
这不是在这种情况下发生的事情,但实际上是,overloading on return type is supported by JVM。这在Scala中暴露给具有不同泛型参数类型的方法,这些类型擦除为相同类型。链接中给出的示例是
object Overload{
def foo(xs : String*) = "foo"; // after erasure is foo:(Seq)String
def foo(xs : Int*) = 3; // after erasure is foo:(Seq)Int
}
答案 2 :(得分:4)
您可能希望查看this question有map
签名的参数返回类型That
。 Martin Odersky的回答解释了如何(以及为什么)可以返回不同的类型。
请注意,返回类型不以任何方式绑定到<{em>到Traversable
,甚至不是目标的参数化类型。例如:
IndexedSeq[Char].map --> String
通过查看StringOps
答案 3 :(得分:3)
虽然the truth is complicated,但我会讨论一个适用同样原则的讨论,但会简化很多事情,以便你可以看到语言中的逻辑。
Scala没有基于返回类型的重载。 (甚至在模式匹配中,模式的“参数”与unapply
的返回类型匹配,从而可以使用返回类型来解决重载。)< / p>
您没有根据返回类型重载map
方法 - 您根据作为参数传递的函数的返回类型重载它。返回类型的更改会更改参数的返回类型,因此您基本上会根据不同的参数类型进行重载。从逻辑上讲,你有类似下列情况的东西:
trait Seq[X]{
def map[Y](func: X => Y) : Seq[Y]
def map[Y,Z](func: X => Tuple2[Y,Z]) : Map[Y,Z]
}
传递给map的函数的返回类型决定了调用哪个版本。
real implementation只是使这个逻辑更加通用和可扩展到Scala库中的许多集合类型,以及许多尚未编写的其他集合类型。
答案 4 :(得分:1)
使用类型类,可以实现不同返回类型的重载:
object AdHocOverloading extends App {
implicit class UnboxOps[T, R, B](b: B)(implicit ev: UnboxEv[T, B, R], ev1: B <:< Box[T]) {
def value: R = ev.unbox(b)
}
val optional = Box(Some(3))
val confident = new Box(Some("C")) with Confidence
val otherType = Seq("bad")
optional.value
confident.value
//otherType.value //compile time error
println(optional.value)
//Some(3)
println(confident.value)
//C
}
trait UnboxEv[+T, -B, +R] {
def unbox(b: B): R
}
trait Confidence
case class Box[+T](v: Option[T]) //v could be private
trait LowLevelImplicitOfBox {
this: Box.type =>
implicit def optionEvidence[T]: UnboxEv[T, Box[T], Option[T]] =
new UnboxEv[T, Box[T], Option[T]] {
override def unbox(b: Box[T]): Option[T] = b.v
}
}
object Box extends LowLevelImplicitOfBox {
implicit def confidentEvidence[T]: UnboxEv[T, Box[T] with Confidence, T] =
new UnboxEv[T, Box[T] with Confidence, T] {
override def unbox(b: Box[T] with Confidence): T = b.v.get
}
}
答案 5 :(得分:0)
这是我正在写的游戏中的一个例子。它会覆盖返回类型:
def consumeItem(item: ConsumableItem) {
executePartyAction[Unit](_.inventory.consumeItem(item, this))
}
def craftItem[ItemType <: Item](recipe: Recipe[ItemType]) = {
executePartyAction[ItemType](_.inventory.craftItem(recipe, this))
}
private def executePartyAction[ReturnType](partyAction: Party => ReturnType): ReturnType = {
party match {
case Some(party) => partyAction(party)
case None => throw new PlayerCharacterMustBelongToAParty
}
}