Универсальный Scala с сопоставлением признаков - PullRequest
0 голосов
/ 22 октября 2018

Посмотрите на этот код.

trait SomeMix {

}

trait Processor[T] {

  def processMix(t: T with SomeMix) = {
    println("processing T with Mix")
  }

  def processAsUsual(t:T)= {
    println("processing T")
  }

  def process(t:T) = {
    t match {
      case mix: SomeMix => processMix(mix) // <---- error here 
      case _ => processAsUsual(t)
    }
  }
}

Глупый компилятор Scala показывает ошибку здесь:

Ошибка: (22, 39) несоответствие типов;найдено: mix.type (с базовым типом SomeMix) требуется: T с SomeMix case mix: SomeMix => processMix (mix)

Он не понимает, что выражение I, совпадающее с SomeMix, уже имеет тип TХорошо, давайте поможем ему.Измененный код:

   def process(t:T) = {
    t match {
      case mix: T with SomeMix => processMix(mix) // <---- warning here 
      case _ => processAsUsual(t)
    }
  }

Теперь он согласен с тем, что все правильно, но показывает предупреждение:

Предупреждение: (22, 17) шаблон абстрактного типа T не проверяется, поскольку он устраняетсяСочетание случая стирания: T с SomeMix => processMix (mix)

Есть ли какой-нибудь хороший способ избежать здесь ошибок и предупреждений?

Ответы [ 4 ]

0 голосов
/ 24 октября 2018

Поскольку, как вы упомянули, это определенно экземпляр T, вы можете просто отключить непроверенное предупреждение:

case mix: (T @unchecked) with SomeMix

Обратите внимание, что оно все еще не проверено, и только во время выполнения проверяет, что матч являетсяэкземпляр SomeMix;если вы измените на например

def process(t: Any) = ...

, вы получите плохие результаты.

0 голосов
/ 23 октября 2018

Компилятор Scala не глупый.Вы не можете проверить, является ли экземпляр T with SomeMix из-за стирания типа.Вместо динамической диспетчеризации типов попробуйте использовать классы типов со статической диспетчеризацией.

Например

trait SomeMix {
  def someMethod: String = "test2"
}

class SomeType

def process[T](t: T)(implicit P: Process[T]): Unit = P.process(t)

trait Process[T] {
  def process(t: T): Unit
}

implicit val processString: Process[SomeType] = s =>
  println(s"processing $s as usual")
implicit val processStringWithSomeMix: Process[SomeType with SomeMix] = s =>
  println(s"processing $s with mix ${s.someMethod}")

process(new SomeType)
process(new SomeType with SomeMix)
0 голосов
/ 24 октября 2018

Вы можете сделать это во время компиляции, как предложено @ppressives.Если вы действительно хотите сделать это во время выполнения, вы должны найти способ сохранить там типы после времени компиляции.В Scala стандартным способом сделать это является TypeTags .

Попробуйте

import reflect.runtime.universe.{TypeTag, typeOf}

def typ[A: TypeTag](a: A) = typeOf[A]

def process(t: T)(implicit ev: TypeTag[T with SomeMix], ev1: TypeTag[T]) = {
  t match {
    case mix if typ(t) <:< typeOf[T with SomeMix] => processMix(mix.asInstanceOf[T with SomeMix])
    case _ => processAsUsual(t)
  }
}

val p = new Processor[Int] {}
p.process(10) //processing T

val p1 = new Processor[Int with SomeMix] {}
val ten = 10.asInstanceOf[Int with SomeMix]
p1.process(ten) //processing T with Mix

Проверка

Шаблонное совпадение списка Scala с генериками

Сопоставление с образцом по универсальному типу в Scala

0 голосов
/ 22 октября 2018

Как это?

trait SomeMix {

}

trait Processor[T] {

  def processMix(t: SomeMix) = {
    println("processing SomeMix")
  }

  def processAsUsual(t:T)= {
    println("processing T")
  }

  def process(t:T) = {
    t match {
      case mix: SomeMix => processMix(mix)
      case _ => processAsUsual(t)
    }
  }
}
...