【问题标题】:Can self typing be used with abstract types?自键入可以与抽象类型一起使用吗?
【发布时间】:2013-06-14 16:03:38
【问题描述】:

我正在尝试在不使用泛型的情况下实现 F 有界多态性。我还需要使用自输入,因为我将引用 this 并期望它被输入为子类型。

trait MyTrait[T] { self: Self => // Compilation error: cannot reference 'Self'
   type Self <: MyTrait[T]

   def doSomethingWithSubtype() {
      ...
   }
}

我可以很容易地使用类型参数(即泛型)来实现这一点,但我想知道我是否遗漏了一些东西来进行上述编译。可以这样使用抽象类型吗?

类似问题:

这些为类似问题提供了解决方法,让我相信上述是不可能的?

F-Bound Polymorphism with Abstract Types instead of Parameter Types?

F-bounded quantification through type member instead of type parameter?

【问题讨论】:

    标签: scala generics scala-2.10


    【解决方案1】:

    您可以将自身类型化为抽象类型,但有一个棘手的限制:它必须在您的 trait 之外定义,但仍以允许实现使用某种类型实现它的方式在范围内。您可以通过将整个事物包装成一个特征来做到这一点:

    trait MyTraitSystem {
        type TraitImpl <: MyTrait
    
        trait MyTrait { self: TraitImpl =>
            def doSomething(t: TraitImpl): String
        }
    }
    
    // with an example implementation of the trait:
    
    object MyImpl extends MyTraitSystem {
      case class TraitImpl(data: String) extends MyTrait {
        def doSomething(t: TraitImpl): String = t.data + " " + data
      }
    }
    

    这等效于使用类型参数的此版本:

    trait MyTrait[T <: MyTrait[_]] { self: T =>
      def doSomething(t: T): String
    }
    
    // with an example implementation of the trait:
    
    case class TraitImpl(data: String) extends MyTrait[TraitImpl] {
      def doSomething(t: TraitImpl): String = t.data + " " + data
    }
    

    除了抽象类型版本的import MyImpl._ 之外,它们可以以相同的方式使用:

    scala> import MyImpl._
        import MyImpl._
    
    scala> val a = TraitImpl("hello")
    a: MyImpl.TraitImpl = TraitImpl(hello)
    
    scala> val b = TraitImpl("world")
    b: MyImpl.TraitImpl = TraitImpl(world)
    
    scala> b.doSomething(a)
    res0: String = hello world
    

    抽象类型的版本更冗长,但它可以工作。您还需要在需要使用TraitImpl 的任何方法/类/...中携带MyTraitSystem 以提供类型:

    object SomewhereElse {
      def doSomethingElse(s: MyTraitSystem)(t: s.TraitImpl) = 
        ??? // s.TraitImpl is the implementation type
    }
    

    对比类型参数版本:

    object SomewhereElse {
      def doSomethingElse[T <: MyTrait[_]](t: MyTrait[T]) = 
        ??? // T is the implementation type
    }
    

    这可能只是几种方法中的一种,但我认为没有任何方法可以与基于类型参数的版本的简洁性相匹配。

    【讨论】:

    • 很好的答案,谢谢。 “抽象类型的版本更冗长,但它确实有效。” - 这样做似乎与我想要实现的目标相反:P 我将继续使用类型参数!
    • @LawrenceWagerfield 是的,它通常是反作用的。不过,它与蛋糕模式配合得很好,这可能是在某些情况下使用它的原因之一。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2021-03-17
    • 2013-07-11
    • 2018-10-06
    • 2011-03-07
    • 2011-12-09
    相关资源
    最近更新 更多