- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
给定一个简单的类层次结构
abstract class Base {}
class A extends Base {}
class B extends Base {}
还有一个类型类
trait Show[T] {
def show(obj: T): String
}
重载实现
class ShowBase extends Show[Base] {
override def show(obj: Base): String = "Base"
}
object ShowA extends ShowBase {
def show(obj: A): String = "A"
}
object ShowB extends ShowBase {
def show(obj: B): String = "B"
}
当执行下面的测试用例时
Seq((new A(), ShowA), (new B(), ShowB)).foreach {
case (obj, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
}
应该生成 (A,A)\n (B,B)
,但生成 (Base,A)\n (Base,B)
。
这是怎么回事?不应调用具有最具体运行时类型的方法 - Polymorphism 101 ?
这个问题看起来类似于 another question其中类型参数阻止正确解析要调用的方法。但是,在我的例子中,类型参数化的 show
方法是随实际实现提供的,与另一个问题中的类型参数化方法形成对比。
扩展 ShowA
实现(ShowB
的类比):
object ShowA extends ShowBase {
def show(obj: A): String = "A"
override def show(obj: Base): String = {
require(obj.isInstanceOf[A], "Argument must be instance of A!")
show(obj.asInstanceOf[A])
}
}
给出预期的输出。问题是将 A
与 ShowB
混合使用会导致异常。
最佳答案
静态重载决议很容易推理:对于适用的方法,仅根据签名选择一个“更具体”的方法。
但是,
scala> Seq((new A(), ShowA), (new B(), ShowB))
res0: Seq[(Base, ShowBase)] = List((A@2b45f918,ShowA$@7ee4acd9), (B@57101ba4,ShowB$@6286d8a3))
在 ShowBase
中没有重载。
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| }
java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1180)
at $anonfun$1.apply(<console>:17)
at $anonfun$1.apply(<console>:16)
at scala.collection.immutable.List.foreach(List.scala:383)
... 38 elided
哦,是的,不要使用 Scala 中的 getSimpleName
。
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(Base,class $line4.$read$$iw$$iw$A)
(Base,class $line5.$read$$iw$$iw$B)
好吧,
scala> class ShowBase extends Show[Base] {
| override def show(obj: Base): String = "Base"
| def show(a: A) = "A" ; def show(b: B) = "B" }
defined class ShowBase
scala> Seq((new A(), new ShowBase), (new B(), new ShowBase))
res3: Seq[(Base, ShowBase)] = List((A@15c3e01a,ShowBase@6eadd61f), (B@56c4c5fd,ShowBase@10a2918c))
scala> res3 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(A,class $line4.$read$$iw$$iw$A)
(B,class $line5.$read$$iw$$iw$B)
很容易想象一个宏使用重载方法 show
为给定接口(interface)生成部分函数。
另一种想法(不一定是好想法)是让编译器在运行时进行选择。
这目前很难在 REPL 中演示。您必须从散落在您的 REPL 历史记录中的对象中导入您想要使用的任何符号。 See the issue.
scala> def imps = $intp.definedSymbolList map (s => $intp.global.exitingTyper { s.fullName }) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res15: Any = A
嘿,成功了!
或者,进入电源模式,将当前相位设置为 typer 并为您提供 intp
,但没有时髦的美元符号。因为我们真的需要更多的钱吗?
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res17: Any = A
如果您想查看未过滤的导入:
scala> intp.isettings.unwrapStrings = false
intp.isettings.unwrapStrings: Boolean = false
scala> imps
res11: String =
"import $line2.$read.$iw.$iw.$intp
import $line3.$read.$iw.$iw.Base
import $line3.$read.$iw.$iw.A
import $line3.$read.$iw.$iw.B
import $line4.$read.$iw.$iw.Show
import $line5.$read.$iw.$iw.ShowA
[snip]
再一次:
scala> abstract class Base ; class A extends Base ; class B extends Base
defined class Base
defined class A
defined class B
scala> trait Show[T <: Base] { def show(obj: T): String }
defined trait Show
scala> class ShowBase extends Show[Base] { override def show(obj: Base): String = "Base" }
defined class ShowBase
scala> object ShowA extends ShowBase { def show(obj: A): String = "A" }
defined object ShowA
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> import tools.reflect._
import tools.reflect._
scala> val tb = reflect.runtime.currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@24e15d95
我有没有提到导入机制很尴尬?
scala> val a = new A
a: A = A@1e5b2860
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res0: Any = A
scala> ShowA show (a: Base)
res1: String = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (a: Base)"))
res2: Any = Base
scala> val a: Base = new A
a: Base = A@7e3a93ce
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
reference to a is ambiguous;
it is imported twice in the same scope by
import a
and import a
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:315)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:197)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:251)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:428)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:443)
... 37 elided
因此,如果您决定要选择哪种类型:
scala> val x: Base = new A
x: Base = A@2647e550
scala> tb.eval(tb.parse(s"$imps ; ShowA show x"))
res4: Any = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (x.asInstanceOf[A])"))
res5: Any = A
关于Scala - 为什么不根据运行时类调用重载方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23091703/
我有一些 Scala 代码,它用两个不同版本的类型参数化函数做了一些漂亮的事情。我已经从我的应用程序中简化了很多,但最后我的代码充满了形式 w(f[Int],f[Double]) 的调用。哪里w()是
如果我在同一目录中有两个单独的未编译的 scala 文件: // hello.scala object hello { def world() = println("hello world") }
val schema = df.schema val x = df.flatMap(r => (0 until schema.length).map { idx => ((idx, r.g
环境: Play 2.3.0/Scala 2.11.1/IntelliJ 13.1 我使用 Typesafe Activator 1.2.1 用 Scala 2.11.1 创建一个新项目。项目创建好后
我只是想知道如何使用我自己的类扩展 Scala 控制台和“脚本”运行程序,以便我可以通过使用实际的 Scala 语言与其通信来实际使用我的代码?我应将 jar 放在哪里,以便无需临时配置即可从每个 S
我已经根据 README.md 文件安装了 ensime,但是,我在低级 ensime-server 缓冲区中出现以下错误: 信息: fatal error :scala.tools.nsc.Miss
我正在阅读《Scala 编程》一书。在书中,它说“一个函数文字被编译成一个类,当在运行时实例化时它是一个函数值”。并且它提到“函数值是对象,因此您可以根据需要将它们存储在变量中”。 所以我尝试检查函数
我有 hello world scala native 应用程序,想对此应用程序运行小型 scala 测试我使用通常的测试命令,但它抛出异常: NativeMain.scala object Nati
有few resources在网络上,在编写与代码模式匹配的 Scala 编译器插件方面很有指导意义,但这些对生成代码(构建符号树)没有帮助。我应该从哪里开始弄清楚如何做到这一点? (如果有比手动构建
我是 Scala 的新手。但是,我用 创建了一个中等大小的程序。斯卡拉 2.9.0 .现在我想使用一个仅适用于 的开源库斯卡拉 2.7.7 . 是吗可能 在我的 Scala 2.9.0 程序中使用这个
有没有办法在 Scala 2.11 中使用 scala-pickling? 我在 sonatype 存储库中尝试了唯一的 scala-pickling_2.11 工件,但它似乎不起作用。我收到消息:
这与命令行编译器选项无关。如何以编程方式获取代码内的 Scala 版本? 或者,Eclipse Scala 插件 v2 在哪里存储 scalac 的路径? 最佳答案 这无需访问 scala-compi
我正在阅读《Scala 编程》一书,并在第 6 章中的类 Rational 实现中遇到了一些问题。 这是我的 Rational 类的初始版本(基于本书) class Rational(numerato
我是 Scala 新手,我正在尝试开发一个使用自定义库的小项目。我在库内创建了一个mysql连接池。这是我的库的build.sbt organization := "com.learn" name :
我正在尝试运行一些 Scala 代码,只是暂时打印出“Hello”,但我希望在 SBT 项目中编译 Scala 代码之前运行 Scala 代码。我发现在 build.sbt 中有以下工作。 compi
Here链接到 maven Scala 插件使用。但没有提到它使用的究竟是什么 Scala 版本。我创建了具有以下配置的 Maven Scala 项目: org.scala-tools
我对 Scala 还很陌生,请多多包涵。我有一堆包裹在一个大数组中的 future 。 future 已经完成了查看几 TB 数据的辛勤工作,在我的应用程序结束时,我想总结上述 future 的所有结
我有一个 scala 宏,它依赖于通过包含其位置的静态字符串指定的任意 xml 文件。 def myMacro(path: String) = macro myMacroImpl def myMacr
这是我的功能: def sumOfSquaresOfOdd(in: Seq[Int]): Int = { in.filter(_%2==1).map(_*_).reduce(_+_) } 为什么我
这个问题在这里已经有了答案: Calculating the difference between two Java date instances (45 个答案) 关闭 5 年前。 所以我有一个这
我是一名优秀的程序员,十分优秀!