加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

避免Scala中的冗余通用参数

发布时间:2020-12-16 08:51:57 所属栏目:安全 来源:网络整理
导读:所以这是一个相当直接的 this Java question到scala的端口 我们有一堆特征,它们采用如下通用参数: trait Ident { } trait Container[I : Ident] { def foo(id: I): String } trait Entity[C : Container[I],I : Ident] { def container: C def foo(id: I) =
所以这是一个相当直接的 this Java question到scala的端口

我们有一堆特征,它们采用如下通用参数:

trait Ident { }

 trait Container[I <: Ident] {
   def foo(id: I): String
 }

 trait Entity[C <: Container[I],I <: Ident] {
   def container: C
   def foo(id: I) = container.foo(id)
 }

这是有效的,但它有点笨拙,因为我们必须在定义Entity的子类时提供Ident的类型和Container的类型.实际上,只有Container的类型就足够了类型信息:

class MyIdent extends Ident { }
class MyContainer extends Container[MyIdent] { } 
class MyEntity extends Entity[MyContainer,MyIdent] { }
//                                        ^^^^^^^ shouldn't really be necessary

使用存在类型避免了实体需要采用两个参数……但是你当然不能在以后引用它.

trait Entity[C <: Container[I] forSome { type I <: Ident }] {
  def container: C
  def foo(id: I) = container.foo(id)
//           ^^^ complains it has no idea what 'I' is here
}

同样地将事物转换为使用成员类型也不起作用……

trait Ident { }

trait Container {
  type I <: Ident
  def foo(id: I): String
}

trait Entity {
  type C <: Container
  def container: C
  def foo(id: C#I) = container.foo(id)
//                                 ^^ type mismatch
}

那么有人知道在Scala中是否有一个优雅的解决方案吗?

解决方法

给出 this answer更新我不确定这是否应该被视为错误

你已经达到了SI-4377;如果你提供明确的type ascriptions,你会得到一个错误,我猜测只是暴露了使用存在性实现的类型预测:

trait Ident { }

trait Container {
  type I <: Ident
  def foo(id: I): String
}

trait Entity {

  type C <: Container
  def container: C
  def foo(id: C#I): String = (container: C).foo(id: C#I)
  // you will get something like: type mismatch;
  // [error]  found   : Entity.this.C#I
  // [error]  required: _3.I where val _3: Entity.this.C
  // as I said above,see https://issues.scala-lang.org/browse/SI-4377
}

说这个(bug?)使得类型成员的泛型编程成为一场噩梦并不是轻描淡写.

但是有一个hack,它包括将值转换为手工制作的自引用类型别名:

case object Container {

  type is[C <: Container] = C with Container {

    type I = C#I
    // same for all other type members,if any
  }

  def is[C <: Container](c: C): is[C] = c.asInstanceOf[is[C]]
}

现在使用它和实体编译:

trait Entity {

  type C <: Container
  def container: C
  def foo(id: C#I): String = Container.is(container).foo(id)
  // compiles!
}

这当然是危险的,并且根据经验,只有当C及其所有类型成员在其将被使用时被绑定到非抽象类型时才是安全的;请注意,情况并非总是如此,因为Scala允许您保留“未定义”类型的成员:

case object funnyContainer extends Container {

  // I'm forced to implement `foo`,but *not* the `C` type member
  def foo(id: I): String = "hi scalac!"
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读