2010-05-02 35 views
9
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) 

Từ ví dụ này có vẻ như phương pháp map bị quá tải trên loại trả về. Quá tải trên loại trả về là không thể đúng? Ai đó có thể giải thích những gì đang xảy ra ở đây không?Quá tải trên loại trả về?

Trả lời

11

map không bị quá tải trên loại trả về. Thay vào đó, có một phương thức với kiểu trả về trừu tượng.

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That 

Trong bytecode, điều này được xoá hoàn toàn để Object:

public abstract java.lang.Object map(scala.Function1, scala.collection.generic.CanBuildFrom); 

Các mô hình được mô tả tốt nhất trên báo Fighting Bit Rot with Types

+2

Đây là điều đáng sợ nhất mà tôi từng thấy kể từ khi tôi bắt đầu lập trình. –

+3

Thật khó để viết phương thức 'bản đồ' này, nhưng thường rất dễ sử dụng. – retronym

+1

@GreenHyena chỉ dành cho nhà phát triển php :) – expert

4

Bạn có thể muốn nhìn vào this question về chữ ký của map mà có kiểu trả về tham số That. Câu trả lời của Martin Odersky giải thích cách thức (và tại sao) các loại khác nhau có thể được trả lại.

Lưu ý rằng loại trả về không bị ràng buộc theo bất kỳ cách nào đến Traversable hoặc thậm chí loại tham số mục tiêu. Ví dụ:

IndexedSeq[Char].map --> String 

Như có thể thấy bằng cách nhìn vào StringOps

+0

Cảm ơn bạn đã liên kết. Tuy nhiên, không hiểu gì cả. Sẽ kiểm tra chủ đề đó một lần nữa sau một vài tháng, khi tôi hy vọng đã trở thành một vô hướng tốt hơn. :-) –

4

Đây không phải là những gì đang xảy ra trong trường hợp này, nhưng thực sự có, overloading on return type is supported by JVM. Điều này được hiển thị trong Scala cho các phương thức có các kiểu đối số chung khác nhau để xóa cùng loại. Ví dụ được cung cấp tại liên kết là

object Overload{ 
    def foo(xs : String*) = "foo"; // after erasure is foo:(Seq)String 
    def foo(xs : Int*) = 3;  // after erasure is foo:(Seq)Int 
} 
0

Đây là ví dụ được lấy từ trò chơi tôi đang viết. Nó sẽ ghi đè các kiểu trả về:

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 
    } 
} 
+1

Điều này không làm quá tải phương thức dựa trên kiểu trả về của phương thức. Nó quá tải một hàm dựa trên kiểu trả về của một hàm được truyền cho phương thức - tức là kiểu tham số của chính phương thức đó. –

2

Trong khi the truth is complicated, tôi sẽ contibute một cuộc thảo luận áp dụng nguyên tắc tương tự nhưng đơn giản hoá mọi thứ rất nhiều vì vậy bạn sẽ nhìn thấy logic trong ngôn ngữ.

Scala không có quá tải dựa trên loại trả về. (Không phải ngay cả trong mô hình phù hợp với nơi "thông số" cho phù hợp với mô hình với kiểu trở của unapply, làm cho nó có thể sử dụng các kiểu trả về để giải quyết tình trạng quá tải.)

Bạn sẽ không quá tải Phương pháp map dựa trên kiểu trả về - bạn đang quá tải nó dựa trên kiểu trả về của hàm được chuyển thành tham số. Sự thay đổi trong kiểu trả về thay đổi kiểu trả về của tham số, do đó bạn về cơ bản quá tải dựa trên các kiểu paramter khác nhau. Vì vậy, nói một cách hợp lý, bạn có điều gì đó tương đương với tình huống sau:

trait Seq[X]{ 
    def map[Y](func: X => Y) : Seq[Y] 
    def map[Y,Z](func: X => Tuple2[Y,Z]) : Map[Y,Z] 
} 

Kiểu trả về của hàm được truyền tới bản đồ xác định phiên bản nào được gọi.

real implementation chỉ làm cho logic này tổng quát hơn và có thể mở rộng được với nhiều loại bộ sưu tập nằm trong thư viện Scala và nhiều loại bộ sưu tập khác chưa được viết.

0

Với typeclass, quá tải với kiểu trả về khác nhau có thể đạt được:

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 
    } 
} 

ví dụ từ: https://github.com/cuzfrog/scala-points#29-ad-hoc-overloading-monkey-patch-method-with-different-return-type

Các vấn đề liên quan