问题
In C# I can overload methods on generic type as shown in the example below:
// http://ideone.com/QVooD
using System;
using System.Collections.Generic;
public class Test {
public static void Foo(List<int> ints) {
Console.WriteLine("I just print");
}
public static void Foo(List<double> doubles) {
Console.WriteLine("I iterate over list and print it.");
foreach(var x in doubles)
Console.WriteLine(x);
}
public static void Main(string[] args) {
Foo(new List<int> {1, 2});
Foo(new List<double> {3.4, 1.2});
}
}
However if I try to do the same in Scala, it will raise a compile time error that List[Int]
and List[Double]
erase to the same type due to erasure. I heard Scala's Manifest
s can be used to work around this, but I don't know how. I didn't find anything helpful in the docs either.
So my question is: How do I use Manifest
s (or whatever else that works) to overload methods over generic types that erase to same type due to erasure?
回答1:
The Manifest won't really help either becuase those will have the same type after erasure.
What will help having different numbers of arguments (or different types after erasure). I find having different numbers of implicit arguments can transparently solve this problem, and by using scala.Predef.DummyImplicit
, you don't even have to import an implicit anywhere.
class Test{
def foo(ints : List[Int])
def foo(doubles : List[Double])(implicit i1:DummyImplicit)
def foo(strings : List[String])(implicit i1:DummyImplicit, i2:DummyImplicit)
}
回答2:
You would not do it like that in Scala. Why try to emulate something that can never work properly given JVM restrictions? Try idiomatic Scala instead:
trait Fooable[T] {
def foo : Unit
}
object IntListFoo extends Fooable[List[Int]] {
def foo {
println("I just print")
}
}
class DoubleListFoo(val l : List[Double]) extends Fooable[List[Double]] {
def foo {
println("I iterate over list and print it.")
l.foreach { e =>
println(e)
}
}
}
implicit def intlist2fooable(l : List[Int]) = IntListFoo
implicit def doublelist2fooable(l : List[Double]) = new DoubleListFoo(l)
Then, you can execute code like
List(1,2,3,4).foo
List(1.0,2.0,3.0).foo
回答3:
Kinda hackish, and both methods need the same return type (here: Unit)...
def fooInt(list: List[Int]) = println("int")
def fooDouble(list: List[Double]) = println("double")
def foo[N <: AnyVal](list:List[N])(implicit m:ClassManifest[N]) = m.erasure match {
case c if c == classOf[Int] => fooInt(list.asInstanceOf[List[Int]])
case c if c == classOf[Double] => fooDouble(list.asInstanceOf[List[Double]])
case _ => error("No soup for you!")
}
foo(List(1,2,3,4))
//--> int
foo(List(1.0,2.0,3.0))
//--> double
来源:https://stackoverflow.com/questions/4982552/scala-method-overloading-over-generic-types