【问题标题】:Self-type annotation for class with higher kinded type具有更高种类类型的类的自类型注释
【发布时间】:2020-04-15 21:42:48
【问题描述】:

给定:

abstract class Databases[F[_]]

我怎样才能使这个特性发挥作用:

// Marker trait signalling the database plugin supports StaticRoles
trait StaticRoles { this: Databases[_] => }

我想确保StaticRoles 只混入同样扩展Databases 的类中,但是我不关心类型参数F 的具体值。

代码返回:

error: _$1 takes no type parameters, expected: one

这是公平的,但是它返回相同的错误:

trait StaticRoles { this: Databases[_[_]] => }

我也试过了:

trait StaticRoles { this: Databases[({type T[X[_]]})#T] => }

这给出了错误:

error: kinds of the type arguments (AnyRef{type T[X[_]]}#T) do not conform to the expected kinds of the type parameters (type F) in class Databases.
       AnyRef{type T[X[_]]}#T's type parameters do not match type F's expected parameters:
       type X has one type parameter, but type _ has none

【问题讨论】:

    标签: scala existential-type higher-kinded-types self-type


    【解决方案1】:

    正确的是

    trait StaticRoles { this: (Databases[F] forSome { type F[_] }) => }
    

    Is there a shorthand for type variable 'm forSome { type m[O] <: UpperBound[O] }` in Scala?

    并非每个存在类型都可以用下划线表示或(在这种情况下)允许用下划线表示。

    还有

    trait StaticRoles { this: Databases[F forSome { type F[_] }] => }
    

    不同于前者,但相同

    trait StaticRoles { this: Databases[Any] => }
    

    因为

    implicitly[(Databases[F forSome { type F[_] }]) =:= Databases[Any]]
    

    Any 实际上是多类的)。

    Databases[Any]Databases[F] forSome { type F[_] } 的子类型

    implicitly[Databases[Any] <:< (Databases[F] forSome { type F[_] })]
    

    使用类型投影 (#) 正确的是

    trait StaticRoles { this: Databases[({ type F[_] })#F] => }
    

    Databases[({ type F[_] })#F] 也是Databases[F] forSome { type F[_] } 的子类型(与Databases[Any] 不可比较,因为Databases 是不变的)。

    Databases[F] forSome { type F[_] }Databases[Any]Databases[({ type F[_] })#F]这三种类型中,只有第一种适用

    trait IO[_]
    
    class Abc extends Databases[IO] with StaticRoles // compiles
    
    //class Abc1 extends StaticRoles // doesn't compile
    

    【讨论】:

    • @AndreyTyukin 是的,只有这两个是。
    • 不错!我不知何故完全错过了this one。谢谢。
    • 是否可以使用 kind 投影仪进行类型投影的版本?
    • @SimãoMartins No. Kind 投影仪简化了 lambda 类型,这里没有 lambda 类型。
    • @SimãoMartins 实际上类型投影版本和Databases[Any] 都不能按预期使用 self-type 和 mixin。只有forSome 可以。请参阅Abc 类的示例以更新我的答案。
    【解决方案2】:

    我认为你应该定义如下:

    
      abstract class Databases[F[_]]
    
      trait StaticRoles[F[_]] { this: Databases[F] =>
    
        def abc: String
      }
    
      class Abc extends Databases[IO] with StaticRoles[IO] {
        override def abc: String = ???
      }
    

    注意:如果您删除 Databases[IO] 并像这样定义

    class Abc extends StaticRoles[IO] {...}
    

    这不会编译。我认为这就是您想要实现的目标

    【讨论】:

      猜你喜欢
      • 2017-11-03
      • 2016-10-26
      • 1970-01-01
      • 1970-01-01
      • 2018-12-09
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多