为什么没有为不同的返回类型定义方法重载?

gnu*_*nce 9 oop methods scala overloading

在Scala中,您可以通过使用共享公共名称但具有不同arities或不同参数类型的方法来重载方法.我想知道为什么这也没有扩展到方法的返回类型?请考虑以下代码:

class C {
  def m: Int = 42
  def m: String = "forty two"
}

val c = new C
val i: Int = C.m
val s: String = C.m
Run Code Online (Sandbox Code Playgroud)

有什么理由不适用吗?

谢谢,

文森特.

Eas*_*sun 8

实际上,你可以通过"隐含"的魔力使它发挥作用.如下:

scala> case class Result(i: Int,s: String)

scala> class C {
     |     def m: Result = Result(42,"forty two")
     | }

scala> implicit def res2int(res: Result) = res.i

scala> implicit def res2str(res: Result) = res.s

scala> val c = new C

scala> val i: Int = c.m

i: Int = 42


scala> val s: String = c.m

s: String = forty two

scala>
Run Code Online (Sandbox Code Playgroud)


oxb*_*kes 6

你当然可以有超载的,其返回类型不同,只是不适合哪些不同方法的方法只有通过返回类型.例如,这很好:

def foo(s: String) : String = s + "Hello"
def foo(i: Int) : Int = i + 1
Run Code Online (Sandbox Code Playgroud)

除此之外,你的问题的答案显然是一个设计决定:返回类型是方法签名的一部分,因为任何有经验的人都AbstractMethodError可以告诉你.

但是请考虑如何允许这样的重载可以与子类型一起使用:

class A {
  def foo: Int = 1
}
val a: A = //...lookup an A
val b = a.foo
Run Code Online (Sandbox Code Playgroud)

这当然是完全有效的代码,并且javac将唯一地解析方法调用.但是如果我将子类分类A如下:

class B extends A {
  def foo: String = "Hello"
}
Run Code Online (Sandbox Code Playgroud)

这会导致原始代码解析被调用的方法被破坏.应该b是什么?我通过对某些现有类进行子类型化来逻辑地破坏了一些现有代码,即使我没有更改该代码或该类.

  • a的静态类型是A,而A只有一个名为foo的方法(返回Int的方法),那么歧义是什么? (2认同)

小智 6

主要原因是复杂性问题:使用"正常"编译器方法,从内到外(从内部表达式到外部范围),逐步构建二进制文件; 如果添加仅返回类型的区分,则需要更改为回溯方法,这会大大增加编译时间,编译器复杂性(=错误!).

此外,如果您返回一个可以自动转换为另一个的子类型或类型,您应该选择哪种方法?您会为完全有效的代码提供歧义错误.

不值得麻烦.

总而言之,您可以轻松地重构代码以避免仅返回类型的重载,例如通过添加要返回的类型的虚拟参数.