如何从类型中提取类型参数

时间:2019-09-01 02:47:40

标签: scala generics types

给出以下类别:

abstract class Foo[B] 
abstract class Baz[B, F <: Foo[B]] {
    def get(foo: F): B
    // other methods
} 

我讨厌在Baz中需要两个类型参数,如果第一个是冗余的。我想写这样的东西:

abstract class Baz[F <: Foo[B]] {
  def get(foo: F): B
}

我是否可以在不采用多个类型参数的情况下引用Baz中的B类型(属于F)?感觉应该有可能,但是我似乎无法弄清楚语法。

2 个答案:

答案 0 :(得分:4)

  1. 您可以使B成为类型成员而不是类型参数吗?

    abstract class Foo { type B }
    abstract class Baz[F <: Foo] {
      def get(foo: F): F#B
      // other methods
    }
    

    然后,如果同时需要type参数和type成员,则可以使用Aux-pattern

    abstract class Foo { type B }
    // Foo.Aux[B] instead of Foo[B]
    object Foo {
      type Aux[B0] = Foo { type B = B0 }
    }
    abstract class Baz[F <: Foo] {
      def get(foo: F): F#B
      // other methods
    }
    
  2. 您可以使F种类更多并且get多态吗? (看起来像一种“无标签最终”方法。)

    abstract class Foo[B]
    abstract class Baz[F[X] <: Foo[X]] {
      def get[B](foo: F[B]): B
      // other methods
    }
    
  3. 您可以将Foo设为类型类吗?

    abstract class Foo[F] {
      type B
    }
    object Foo {
      type Aux[F, B0] = Foo[F] { type B = B0 }
      def instance[F, B0]: Aux[F, B0] = new Foo[F] { type B = B0 }
    
      //instead of  class F1 extends Foo[B1]
      implicit val foo1: Aux[F1, B1] = instance
    }
    
    abstract class Baz[F](implicit val foo: Foo[F]) {
      def get: foo.B
      // other methods
    }
    

    abstract class Baz[F: Foo] {
      val foo: Foo[F] = implicitly
      def get: foo.B
      // other methods
    }
    
  4. 您可以将两个类型参数提取到新类中吗?

    abstract class Foo[B]
    
    abstract class Tuple {
      type B
      type F <: Foo[B]
    }
    
    abstract class Baz[T <: Tuple] {
      def get(foo: T#F): T#B
      // other methods
    }
    

    abstract class Baz[T <: Tuple](t: T) {
      def get(foo: t.F): t.B
      // other methods
    }
    

答案 1 :(得分:2)

  

当第一个是多余的时,我讨厌在Baz中需要两个类型参数。

没有冗余。如果Baz代码引用了2种不同的类型,那么我们需要为它们使用2种不同的名称(FBXY,或THISTHAT都没关系)。

如果Baz代码仅引用1种类型,但是该类型需要限制为Foo已经实现的某种类型,则可以添加该限制:

class Baz[X](implicit ev: Foo[X]) { ...

这可以简化为:

class Baz[X: Foo] { ...

如果无法推断类型,并且您希望简化实例创建,则可以使用类型成员/别名。

abstract class Baz[B] {
  type F = Foo[B]
  def get(foo: F): B
}

但是将内容写出来通常更清楚。

abstract class Baz[B] {
  def get(foo: Foo[B]): B
}

但是,这当然消除了子类型的可能性。