Перегрузка на типе возврата?

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 метод перегружается на типе возврата. Перегрузка на типе возврата не является возможным правом? Кто-то объяснил бы, что продолжается здесь?

12
задан Thomas Jung 18 May 2010 в 07:10
поделиться

5 ответов

Возможно, вы захотите взглянуть на этот вопрос о сигнатуре map, который имеет параметрический возвращаемый тип That. Ответ Мартина Одерски объясняет, как (и почему) могут быть возвращены различные типы.

Обратите внимание, что возвращаемый тип не связан каким-либо образом с Traversable или даже с параметризованным типом цели. Например:

IndexedSeq[Char].map --> String

Как видно из StringOps

4
ответ дан 2 December 2019 в 05:27
поделиться

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);

Шаблон лучше всего описан в статье Борьба с битовой гнилью с помощью типов

13
ответ дан 2 December 2019 в 05:27
поделиться

Вот пример из игры, которую я пишу. Он переопределяет возвращаемый тип:

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
    }
}
0
ответ дан 2 December 2019 в 05:27
поделиться

Хотя истина сложна, я собираюсь привести рассуждение, в котором применяется тот же принцип, но все сильно упрощается, чтобы вы могли увидеть логику в языке.

В Scala нет перегрузки на основе возвращаемого типа. (Даже в паттерн-сопоставлении, где "параметры" паттерна совпадают с возвращаемым типом unapply, что позволяет использовать возвращаемый тип для разрешения перегрузки).

Вы не перегружаете метод 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, определяет, какая версия будет вызвана.

реальная реализация просто делает эту логику более общей и расширяемой на множество типов коллекций, которые есть в библиотеке Scala, и на множество других типов коллекций, которые еще не написаны.

4
ответ дан 2 December 2019 в 05:27
поделиться

Это не то, что происходит в данном случае, но на самом деле да, перегрузка по возвращаемому типу поддерживается 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
}
6
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: