scala - 转换 "hollow"更高种类的类型值以避免实例化

标签 scala casting type-erasure higher-kinded-types

我发现自己在观看 Scalawags#2 的一段录音,然后出现了关于类型删除的部分,Dick Wall 指出反射最终会咬住你的脚。

所以我在思考我经常做的事情(我也看到了 Scala 集合的实现)。假设我有一个带有序列化器的系统,该序列化器将系统作为类型参数:

trait Sys[S <: Sys[S]] { type Tx }
trait FooSys extends Sys[FooSys]

trait Serializer[S <: Sys[S], A] {
  def read(implicit tx: S#Tx): A
}

现在有许多类型A可以在没有值参数的情况下构建序列化器,因此本质上系统类型参数是“空的”。由于在我的示例中大量调用了序列化程序,因此我正在保存实例化:

object Test {
  def serializer[S <: Sys[S]] : Serializer[S, Test[S]] =
    anySer.asInstanceOf[Ser[S]]

  private val anySer = new Ser[FooSys]

  private final class Ser[S <: Sys[S]] extends Serializer[S, Test[S]] {
    def read(implicit tx: S#Tx) = new Test[S] {} // (shortened for the example)
  }
}
trait Test[S <: Sys[S]]

知道这是正确的,但是,asInstanceOf 当然有难闻的气味。对于这种方法有什么建议吗?让我添加两件事

  • 将类型参数从特征Serializer的构造函数移动到read方法不是一个选项(有特定的序列化器需要在S中参数化值参数)
  • 不可以向 Serializer 的类型构造函数参数添加差异

最佳答案

简介:

我对你的例子有点困惑,我可能误解了你的问题,我有一种感觉 S 之间存在某种类型的递归。和Tx我没有从你的问题中得到答案(因为如果不是, S#Tx 可能是任何东西,我不明白 anySer 的问题)

暂定答案:

在编译时,对于 Ser[T] 的任何实例将有一个明确定义的类型参数 T ,因为您想在实例化时保存它,所以您将有一个 anySer Ser[T]对于给定的特定类型 A

您在某种程度上所说的是 Ser[A]将作为 Ser[S]对于任何 S 。根据类型A和S之间的关系,这可以用两种方式解释。

  1. 如果每个 A<:<S 都可以进行此转换那么你的序列化器是 COVARIANT你可以将你的anySer初始化为 Ser[Nothing] 。由于 Nothing 是 Scala 中每个类的子类,因此您的 anySer 将始终以 Ser[Whatever] 的方式工作。

  2. 如果每个 S<:<A 都可以进行此转换那么你的序列化器是 CONTRAVARIANT你可以将你的anySer初始化为 Ser[Any] 。由于 Any 是 Scala 中每个类的子类,因此您的 anySer 将始终作为 Ser[Whatever] 工作。

  3. 如果不是前一种情况,则意味着:

    def serializer[S <: Sys[S]] : Serializer[S, Test[S]] =
    anySer.asInstanceOf[Ser[S]]
    

    可能会在运行时产生可怕的失败,因为有一些 S 序列化器无法工作。如果不存在可能发生这种情况的 S,那么您的类(class)属于 1 或

评论后编辑

如果您的类型确实是不变的,则通过强制转换进行的转换会破坏不变关系。您基本上是在强制类型系统执行不自然的转换,因为根据您对所编写代码的了解,您知道不会发生任何错误。如果是这种情况,那么强制转换是正确的方法:您正在强制使用与编译器可以正式检查的类型不同的类型,并且您正在明确这一点。我什至会写一个大评论说为什么你知道操作是合法的并且编译器无法猜测并最终附加一个漂亮的单元测试来验证“非正式”关系始终成立。

总的来说,我认为这种做法应该非常小心地使用。强类型语言的好处之一是编译器执行正式的类型检查,帮助您捕获早期错误。如果你故意破坏它,你就放弃了这个大好处。

关于scala - 转换 "hollow"更高种类的类型值以避免实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14397548/

相关文章:

scala - Scala中的类型删除

json - scala,读取JSON字符串并从JSON数组中返回特定值

c++ - 来自 dll 的函数调用 [表观调用括号前的表达式必须具有(指向)函数类型]

java - 奇怪的泛型行为。早早被抹杀?

java - 将 Set.toArray() 转换为 Object[] 时出错

c - 指向函数原型(prototype)的指针

java 类型删除与 Field#getGenericType 和 Method#getGenericReturnType

scala - 按名称调用参数

java - 如何使用 Scala REPL 来测试 java 代码 - java 和 scala REPL 给出不同的输出

generics - 在 Scala 中是否可以强制调用者为多态方法指定类型参数?