Тип класса и импликиты с одноэлементным типом / объектом case - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь реализовать класс типов, который работает с объектами case вместо классов.Это вроде работает.Когда я передаю сам объект case функции, он работает, однако, когда я пытаюсь передать объект с типом базовой черты, он не компилируется.

object Test {

  sealed trait MyType
  case object Type1 extends MyType
  case object Type2 extends MyType

  trait Builder[A] {
    def build: String
  }

  object Builder {
    implicit  val type1Builder: Builder[Type1.type] = new Builder[Type1.type] {
      def build: String = s"building1"
    }

    implicit val type2Builder: Builder[Type2.type] = new Builder[Type2.type] {
      def build: String = s"building2"
    }

    def build[A](a: A)(implicit builder: Builder[A]) = builder.build
  }

  import Builder._

  // Compiles
  def test[T <: MyType](t:Type2.type): Unit = {
    println(Builder.build(t))
  }
  // Doesn't compile - 'could not find implicit value for parameter builder ' 
  def test2[T <: MyType](t:MyType): Unit = {
    println(Builder.build(t))
  }
}

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Это потому, что параметры типа в Scala по умолчанию инвариантны, это означает, что:

Builder [Type1.type] не является подтипом Builder [MyType].

В этом блокеваш код, вам нужен Builder [MyType], и ​​ни type1Builder, ни type2Builder не являются подтипами Builder [MyType]:

def test[T <: MyType](t:MyType): Unit = {
    println(Builder.build(t))
}

Вы можете сделать параметр типа Builder ковариантным (Builder [+ A]), но затеми type1Builder, и type2Builder будут кандидатами для этого неявного, так что он снова потерпит неудачу.

Что вам нужно сделать, это использовать в вашем тестовом методе границу Context, а не верхнюю границу типа, как показано ниже:

def test[T : Builder](t: T): Unit = {
   println(Builder.build(t))
}

Это означает, что тест получает тип T, который является членом класса типа Builder, и Type1, и Type2 являются членами класса типа Builder, поскольку есть Builder [Type1.type] и Builder [Type2.type] в неявной области видимости.

Если вы также хотите ограничить тестирование, чтобы его можно было вызывать только с реализациями MyType, вы можете использовать как верхнюю границу типа, так и контекстную границу.:

def test[T <: MyType : Builder](t: T): Unit = {
    println(Builder.build(t))
}


test(Type1) // building1
test(Type2) // building2
0 голосов
/ 27 сентября 2018

Каким-то образом это сработало для меня.Не уверен, почему

 def test2[T <: MyType : Builder ](t2:T): Unit = {

    println(Builder.build(t2))
  }
...