scala 3 内联失败一个非常简单的例子
scala 3 inlining fails a very simple example
我正在探索 scala3 内联的可能性。我编写了一个简单的示例,我希望在编译时应用构造密封 class 的验证方法:
import scala.compiletime.{ error, codeOf }
sealed abstract class OneOrTwo(val code: String)
object OneOrTwo {
case object One extends OneOrTwo("one")
case object Two extends OneOrTwo("two")
def from(s: String): Option[OneOrTwo] =
s match {
case One.code => Some(One)
case Two.code => Some(Two)
case _ => None
}
inline def inlinedFrom1(s: String): OneOrTwo = {
inline s match {
case "one" => One
case "two" => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
val test1 = OneOrTwo.inlinedFrom1("one") // compiles
val test12 = OneOrTwo.inlinedFrom1("three") // doesn't compile as expected -> can't make a OneOrTwo out of "three"
}
到目前为止,还不错。但我真正想要的是能够在内联函数中重新使用 from
函数。这是我的尝试:
// this goes in the OneOrTwo companion object as well
inline def inlinedFrom2(s: String): OneOrTwo = {
from(s).getOrElse(error("can't make a OneOrTwo out of " + codeOf(s)))
}
inline def inlinedFrom3(s: String): OneOrTwo = {
s match {
case One.code => One
case Two.code => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
val test2 = OneOrTwo.inlinedFrom2("one") // doesn't compile -> can't make a OneOrTwo out of "one"
val test3 = OneOrTwo.inlinedFrom3("one") // doesn't compile -> can't make a OneOrTwo out of "one"
inlinedFrom3
是一种概括,表明如果我直接匹配对象的代码,编译器看不到它们与输入字符串相同,并采取了错误的分支。
我想了解的是为什么 inlinedFrom3
不起作用以及是否有办法让它起作用。
注意:我使用的是 scala 3.0.0-RC2
好问题,
首先,考虑内联是一种在编译时在 Scala 中执行元编程的方法(正如您在示例中所做的那样)。
为了解决您的问题,这里编译器不理解 One.code
是 "one"
类型。
实际上,如果您尝试打印 One.code
,编译器输出为:
OneOrTwo.One.code
而不是
"one"
等等,为什么?因为编译器无法在编译时推断出有关 One.code 的任何信息。要将缺少的信息提供给编译器,您可以:
- 指定单例字符串类型
sealed trait OneOrTwo {
val code: String
}
object OneOrTwo {
case object One extends OneOrTwo {
override val code : "one" = "one"
}
case object Two extends OneOrTwo {
override val code : "two" = "two"
}
}
- 内联
val
定义
sealed trait OneOrTwo {
val code: String
}
object OneOrTwo {
case object One extends OneOrTwo {
override inline val code = "one"
}
case object Two extends OneOrTwo {
override inline val code = "two"
}
}
即使进行了此修改,您的代码仍然无法编译。这是由未内联的匹配子句引起的。实际上,如前所述 here、error 方法提供了一种发出自定义错误消息的方法。如果对错误的调用是内联的并且没有作为死分支消除,则会发出错误。
因此,如果您将 error(...)
放在未内联的代码中,将始终抛出错误。
例如,这段代码:
if(false) { error("thrown..") } { }
产生编译错误。
最后,为了解决你的问题,你需要内联你的匹配子句:
inline def inlinedFrom3(s: String): OneOrTwo = {
inline s match {
case One.code => One
case Two.code => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
编译(inlinedFrom3
)成功。 inlineFrom2
由于上述问题继续失败。
我正在探索 scala3 内联的可能性。我编写了一个简单的示例,我希望在编译时应用构造密封 class 的验证方法:
import scala.compiletime.{ error, codeOf }
sealed abstract class OneOrTwo(val code: String)
object OneOrTwo {
case object One extends OneOrTwo("one")
case object Two extends OneOrTwo("two")
def from(s: String): Option[OneOrTwo] =
s match {
case One.code => Some(One)
case Two.code => Some(Two)
case _ => None
}
inline def inlinedFrom1(s: String): OneOrTwo = {
inline s match {
case "one" => One
case "two" => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
val test1 = OneOrTwo.inlinedFrom1("one") // compiles
val test12 = OneOrTwo.inlinedFrom1("three") // doesn't compile as expected -> can't make a OneOrTwo out of "three"
}
到目前为止,还不错。但我真正想要的是能够在内联函数中重新使用 from
函数。这是我的尝试:
// this goes in the OneOrTwo companion object as well
inline def inlinedFrom2(s: String): OneOrTwo = {
from(s).getOrElse(error("can't make a OneOrTwo out of " + codeOf(s)))
}
inline def inlinedFrom3(s: String): OneOrTwo = {
s match {
case One.code => One
case Two.code => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
val test2 = OneOrTwo.inlinedFrom2("one") // doesn't compile -> can't make a OneOrTwo out of "one"
val test3 = OneOrTwo.inlinedFrom3("one") // doesn't compile -> can't make a OneOrTwo out of "one"
inlinedFrom3
是一种概括,表明如果我直接匹配对象的代码,编译器看不到它们与输入字符串相同,并采取了错误的分支。
我想了解的是为什么 inlinedFrom3
不起作用以及是否有办法让它起作用。
注意:我使用的是 scala 3.0.0-RC2
好问题,
首先,考虑内联是一种在编译时在 Scala 中执行元编程的方法(正如您在示例中所做的那样)。
为了解决您的问题,这里编译器不理解 One.code
是 "one"
类型。
实际上,如果您尝试打印 One.code
,编译器输出为:
OneOrTwo.One.code
而不是
"one"
等等,为什么?因为编译器无法在编译时推断出有关 One.code 的任何信息。要将缺少的信息提供给编译器,您可以:
- 指定单例字符串类型
sealed trait OneOrTwo {
val code: String
}
object OneOrTwo {
case object One extends OneOrTwo {
override val code : "one" = "one"
}
case object Two extends OneOrTwo {
override val code : "two" = "two"
}
}
- 内联
val
定义
sealed trait OneOrTwo {
val code: String
}
object OneOrTwo {
case object One extends OneOrTwo {
override inline val code = "one"
}
case object Two extends OneOrTwo {
override inline val code = "two"
}
}
即使进行了此修改,您的代码仍然无法编译。这是由未内联的匹配子句引起的。实际上,如前所述 here、error 方法提供了一种发出自定义错误消息的方法。如果对错误的调用是内联的并且没有作为死分支消除,则会发出错误。
因此,如果您将 error(...)
放在未内联的代码中,将始终抛出错误。
例如,这段代码:
if(false) { error("thrown..") } { }
产生编译错误。
最后,为了解决你的问题,你需要内联你的匹配子句:
inline def inlinedFrom3(s: String): OneOrTwo = {
inline s match {
case One.code => One
case Two.code => Two
case _ => error("can't make a OneOrTwo out of " + codeOf(s))
}
}
编译(inlinedFrom3
)成功。 inlineFrom2
由于上述问题继续失败。