如何标准化联合类型 (T | Option[T])?
How to normalise a Union Type (T | Option[T])?
我有以下 case class
:
case class Example[T](
obj: Option[T] | T = None,
)
这让我可以像 Example(myObject)
那样构造它,而不是 Example(Some(myObject))
。
要使用 obj,我需要将其规范化为 Option[T]
:
lazy val maybeIn = obj match
case o: Option[T] => o
case o: T => Some(o)
the type test for Option[T] cannot be checked at runtime
我尝试使用 TypeTest
但我也收到警告 - 或者我发现的解决方案看起来非常复杂 - 请参阅
有没有更好的方法在 Scala 3 中实现这种模式?
我不知道 Scala3。但你可以简单地这样做:
case class Example[T](v: Option[T] = None)
object Example {
def apply[T](t: T): Example[T] = Example(Some(t))
}
编辑:以下答案不正确。从 Scala 3.1 开始,流分析只能检查可空性。有关更多信息,请访问 Scala book.
我认为已经给出的答案可能更适合您提出的用例(公开一个 API 可以采用一个简单的值并将其规范化为一个 Option
)。
不过,标题中的问题还是很有意思,我觉得有必要解决一下。
您所观察到的是类型参数在运行时被擦除的结果,即它们仅在编译期间存在,而匹配发生在运行时,一旦它们被已删除.
但是,Scala 编译器能够对联合类型执行流分析。直觉上我会说可能有一种方法可以让它在模式匹配中工作(就像你所做的那样),但是你可以使用 if
和 isInstanceOf
确保它工作(不那么干净,我同意):
case class Example[T](
obj: Option[T] | T = None
) {
lazy val maybeIn =
if (obj.isInstanceOf[Option[_]]) {
obj
} else {
Some(obj)
}
}
您可以尝试使用此代码 here on Scastie。
Here 是 2019 年将流分析添加到编译器时的公告。
我们有一个 specialized Option
-like type for this purpose: OptArg
(在 Scala 2 中,但应该很容易移植到 3)
import com.avsystem.commons._
def gimmeLotsOfParams(
intParam: OptArg[Int] = OptArg.Empty,
strParam: OptArg[String] = OptArg.Empty
): Unit = ???
gimmeLotsOfParams(42)
gimmeLotsOfParams(strParam = "foo")
它依赖于隐式转换,因此您必须谨慎使用它,即不要将它用作 Option
.
的直接替代品
OptArg
的实现非常简单,如果您不需要外部依赖项,那么您可以将它复制到您的项目或某种“公共”库中。
我有以下 case class
:
case class Example[T](
obj: Option[T] | T = None,
)
这让我可以像 Example(myObject)
那样构造它,而不是 Example(Some(myObject))
。
要使用 obj,我需要将其规范化为 Option[T]
:
lazy val maybeIn = obj match
case o: Option[T] => o
case o: T => Some(o)
the type test for Option[T] cannot be checked at runtime
我尝试使用 TypeTest
但我也收到警告 - 或者我发现的解决方案看起来非常复杂 - 请参阅
有没有更好的方法在 Scala 3 中实现这种模式?
我不知道 Scala3。但你可以简单地这样做:
case class Example[T](v: Option[T] = None)
object Example {
def apply[T](t: T): Example[T] = Example(Some(t))
}
编辑:以下答案不正确。从 Scala 3.1 开始,流分析只能检查可空性。有关更多信息,请访问 Scala book.
我认为已经给出的答案可能更适合您提出的用例(公开一个 API 可以采用一个简单的值并将其规范化为一个 Option
)。
不过,标题中的问题还是很有意思,我觉得有必要解决一下。
您所观察到的是类型参数在运行时被擦除的结果,即它们仅在编译期间存在,而匹配发生在运行时,一旦它们被已删除.
但是,Scala 编译器能够对联合类型执行流分析。直觉上我会说可能有一种方法可以让它在模式匹配中工作(就像你所做的那样),但是你可以使用 if
和 isInstanceOf
确保它工作(不那么干净,我同意):
case class Example[T](
obj: Option[T] | T = None
) {
lazy val maybeIn =
if (obj.isInstanceOf[Option[_]]) {
obj
} else {
Some(obj)
}
}
您可以尝试使用此代码 here on Scastie。
Here 是 2019 年将流分析添加到编译器时的公告。
我们有一个 specialized Option
-like type for this purpose: OptArg
(在 Scala 2 中,但应该很容易移植到 3)
import com.avsystem.commons._
def gimmeLotsOfParams(
intParam: OptArg[Int] = OptArg.Empty,
strParam: OptArg[String] = OptArg.Empty
): Unit = ???
gimmeLotsOfParams(42)
gimmeLotsOfParams(strParam = "foo")
它依赖于隐式转换,因此您必须谨慎使用它,即不要将它用作 Option
.
OptArg
的实现非常简单,如果您不需要外部依赖项,那么您可以将它复制到您的项目或某种“公共”库中。