Scala.js 隐式转换不起作用...有时?
Scala.js implicit conversions don't work... sometimes?
我不太明白为什么从 Scala 到 JS 值的隐式转换不能这样工作:
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
trait X extends js.Object {
def map(f: js.Function1[Int, String]) = js.native
def mapScala(f: Function1[Int, String]) = js.native // just for demo purpose, this is not really part of type X
def create(maybe: js.UndefOr[Int]) = js.native
}
def test(x: X) {
// I want these two lines to compile, but they don't
x.map(a => "yo") // error: missing parameter type
x.create(None) // error: type mismatch. Found None.type, required: js.UndefOr[Int]
// This works, but is too verbose
x.map((a: Int) => "yo") // only if arg type specified like this
x.mapScala(a => "yo") // because mapScala expects a Scala Function1
x.create(JSRichOption(None).orUndefined) // because value is manually converted
}
我是否试图以错误的方式使用隐式转换? classX
的实现是外部提供的,在Javascript中。在我的代码中,我想将本机 Scala 值传递给 X
的方法,我不想每次都手动进行转换。
我知道 Scala.js 有另一种方法 – 为我的类型 X
like this 拉皮条,但我正在努力避免这种情况,因为它有更多的样板和更多的对象将在运行时以这种方式实例化。不管怎样,我仍然想了解为什么我的代码无法正常工作。
map
调用不起作用的原因是 Scala 类型推断器的局限性:它需要在寻找隐式转换之前解析完整类型。然而,Scala 2.12 带来了 SAM treatement 就像 Java。粗略地说,这意味着您可以编写一个 lambda 而不是匿名 class 使用单个方法实现接口。
因此 x.map(a => "yo")
将扩展为:
// Never (!) write this yourself.
x.map(new js.Function1[Int, String] {
def apply(a: Int): String = "yo"
})
Scala.js 编译器单独处理。您可以使用 -Xexperimental
标志在 Scala 2.11 中启用 SAM 处理。
create
调用不起作用的原因是没有从 Option[T]
到 js.UndefOr[T]
的隐式转换(在 Scala.js 标准库中)。 是 到 JSRichOption[T]
的隐式转换,它启用了 orUndefined
方法。你应该写:
x.create(None.orUndefined)
或者在这种情况下,您可以简单地写:
x.create(js.undefined)
我不太明白为什么从 Scala 到 JS 值的隐式转换不能这样工作:
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
trait X extends js.Object {
def map(f: js.Function1[Int, String]) = js.native
def mapScala(f: Function1[Int, String]) = js.native // just for demo purpose, this is not really part of type X
def create(maybe: js.UndefOr[Int]) = js.native
}
def test(x: X) {
// I want these two lines to compile, but they don't
x.map(a => "yo") // error: missing parameter type
x.create(None) // error: type mismatch. Found None.type, required: js.UndefOr[Int]
// This works, but is too verbose
x.map((a: Int) => "yo") // only if arg type specified like this
x.mapScala(a => "yo") // because mapScala expects a Scala Function1
x.create(JSRichOption(None).orUndefined) // because value is manually converted
}
我是否试图以错误的方式使用隐式转换? classX
的实现是外部提供的,在Javascript中。在我的代码中,我想将本机 Scala 值传递给 X
的方法,我不想每次都手动进行转换。
我知道 Scala.js 有另一种方法 – 为我的类型 X
like this 拉皮条,但我正在努力避免这种情况,因为它有更多的样板和更多的对象将在运行时以这种方式实例化。不管怎样,我仍然想了解为什么我的代码无法正常工作。
map
调用不起作用的原因是 Scala 类型推断器的局限性:它需要在寻找隐式转换之前解析完整类型。然而,Scala 2.12 带来了 SAM treatement 就像 Java。粗略地说,这意味着您可以编写一个 lambda 而不是匿名 class 使用单个方法实现接口。
因此 x.map(a => "yo")
将扩展为:
// Never (!) write this yourself.
x.map(new js.Function1[Int, String] {
def apply(a: Int): String = "yo"
})
Scala.js 编译器单独处理。您可以使用 -Xexperimental
标志在 Scala 2.11 中启用 SAM 处理。
create
调用不起作用的原因是没有从 Option[T]
到 js.UndefOr[T]
的隐式转换(在 Scala.js 标准库中)。 是 到 JSRichOption[T]
的隐式转换,它启用了 orUndefined
方法。你应该写:
x.create(None.orUndefined)
或者在这种情况下,您可以简单地写:
x.create(js.undefined)