Jér*_*ôme 67 scala overloading compilation typeclass type-erasure
我在scala中写了这个,它不会编译:
class TestDoubleDef{
def foo(p:List[String]) = {}
def foo(p:List[Int]) = {}
}
Run Code Online (Sandbox Code Playgroud)
编译通知:
[error] double definition:
[error] method foo:(List[String])Unit and
[error] method foo:(List[Int])Unit at line 120
[error] have same type after erasure: (List)Unit
Run Code Online (Sandbox Code Playgroud)
我知道JVM没有对泛型的原生支持,所以我理解这个错误.
我可以写包装List[String]
,List[Int]
但我很懒:)
我很怀疑,但是,有没有另一种方式表达List[String]
不是同一种类型List[Int]
?
谢谢.
Lan*_*dei 50
我喜欢MichaelKrämer使用implicits的想法,但我认为它可以更直接地应用:
case class IntList(list: List[Int])
case class StringList(list: List[String])
implicit def il(list: List[Int]) = IntList(list)
implicit def sl(list: List[String]) = StringList(list)
def foo(i: IntList) { println("Int: " + i.list)}
def foo(s: StringList) { println("String: " + s.list)}
Run Code Online (Sandbox Code Playgroud)
我认为这是非常易读和直截了当的.
[更新]
还有另一种简单的方法似乎有效:
def foo(p: List[String]) { println("Strings") }
def foo[X: ClassManifest](p: List[Int]) { println("Ints") }
def foo[X: ClassManifest, Y: ClassManifest](p: List[Double]) { println("Doubles") }
Run Code Online (Sandbox Code Playgroud)
对于每个版本,您需要一个额外的类型参数,所以这不会扩展,但我认为对于三个或四个版本它没关系.
[更新2]
对于两种方法,我发现了另一个好方法:
def foo(list: => List[Int]) = { println("Int-List " + list)}
def foo(list: List[String]) = { println("String-List " + list)}
Run Code Online (Sandbox Code Playgroud)
Jea*_*let 50
您可以使用其中DummyImplicit
定义的定义,Predef
而不是发明虚拟隐式值:
class TestMultipleDef {
def foo(p:List[String]) = ()
def foo(p:List[Int])(implicit d: DummyImplicit) = ()
def foo(p:List[java.util.Date])(implicit d1: DummyImplicit, d2: DummyImplicit) = ()
}
Run Code Online (Sandbox Code Playgroud)
Vik*_*ang 10
由于类型擦除的奇迹,您的方法列表的类型参数在编译期间被擦除,因此将两种方法都减少到相同的签名,这是编译器错误.
Aar*_*rup 10
要理解MichaelKrämer的解决方案,有必要认识到隐含参数的类型并不重要.什么是重要的是,它们的类型是不同的.
以下代码以相同的方式工作:
class TestDoubleDef {
object dummy1 { implicit val dummy: dummy1.type = this }
object dummy2 { implicit val dummy: dummy2.type = this }
def foo(p:List[String])(implicit d: dummy1.type) = {}
def foo(p:List[Int])(implicit d: dummy2.type) = {}
}
object App extends Application {
val a = new TestDoubleDef()
a.foo(1::2::Nil)
a.foo("a"::"b"::Nil)
}
Run Code Online (Sandbox Code Playgroud)
在字节码级别,两种foo
方法都成为双参数方法,因为JVM字节码不知道隐式参数或多个参数列表.在调用站点,Scala编译器foo
通过查看传入的列表的类型(直到稍后才擦除)来选择适当的方法来调用(因此传入适当的虚拟对象).
虽然它更冗长,但这种方法减轻了调用者提供隐式参数的负担.实际上,如果dummyN对象是TestDoubleDef
类的私有对象,它甚至可以工作.
正如Viktor Klang所说,泛型类型将被编译器擦除.幸运的是,有一个解决方法:
class TestDoubleDef{
def foo(p:List[String])(implicit ignore: String) = {}
def foo(p:List[Int])(implicit ignore: Int) = {}
}
object App extends Application {
implicit val x = 0
implicit val y = ""
val a = new A()
a.foo(1::2::Nil)
a.foo("a"::"b"::Nil)
}
Run Code Online (Sandbox Code Playgroud)
感谢Michid提示!
如果我结合丹尼尔小号响应 和桑德尔Murakozi这里的回应,我得到:
@annotation.implicitNotFound(msg = "Type ${T} not supported only Int and String accepted")
sealed abstract class Acceptable[T]; object Acceptable {
implicit object IntOk extends Acceptable[Int]
implicit object StringOk extends Acceptable[String]
}
class TestDoubleDef {
def foo[A : Acceptable : Manifest](p:List[A]) = {
val m = manifest[A]
if (m equals manifest[String]) {
println("String")
} else if (m equals manifest[Int]) {
println("Int")
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到一个类型安全的(ISH)变种
scala> val a = new TestDoubleDef
a: TestDoubleDef = TestDoubleDef@f3cc05f
scala> a.foo(List(1,2,3))
Int
scala> a.foo(List("test","testa"))
String
scala> a.foo(List(1L,2L,3L))
<console>:21: error: Type Long not supported only Int and String accepted
a.foo(List(1L,2L,3L))
^
scala> a.foo("test")
<console>:9: error: type mismatch;
found : java.lang.String("test")
required: List[?]
a.foo("test")
^
Run Code Online (Sandbox Code Playgroud)
该逻辑还可以被包括在类型类作为这样(由于jsuereth):@ annotation.implicitNotFound(MSG ="富不支持$ {T】仅int和string接受")密封性状的Foo [T] {DEF申请(列表:列表[T]):单位}
object Foo {
implicit def stringImpl = new Foo[String] {
def apply(list : List[String]) = println("String")
}
implicit def intImpl = new Foo[Int] {
def apply(list : List[Int]) = println("Int")
}
}
def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
Run Code Online (Sandbox Code Playgroud)
这使:
scala> @annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted")
| sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:32: error: Foo does not support Double only Int and String accepted
foo(List(1.0))
^
Run Code Online (Sandbox Code Playgroud)
请注意,我们必须编写,implicitly[Foo[A]].apply(x)
因为编译器认为这 implicitly[Foo[A]](x)
意味着我们implicitly
使用参数调用.
归档时间: |
|
查看次数: |
12670 次 |
最近记录: |