2013-05-18 2 views
4

Указанные классышаблон матч на проявленных экземпляров запечатанного класса

sealed abstract class A 

case class B(param: String) extends A 

case class C(param: Int) extends A 

trait Z {} 

class Z1 extends Z {} 

class Z2 extends Z {} 

def zFor[T <: A : Manifest]: Option[Z] = { 
    val z = manifest[T].erasure 
    if (z == classOf[B]) { 
    Some(new Z1) 
    } else 
    if (z == classOf[C]) { 
    Some(new Z2) 
    } else { 
    None 
    } 
} 

Я думаю, что проблема с совпадающими здесь картина является невозможность построить шаблон сопоставления таблицы в байткод. Существует ли какое-либо решение этой проблемы? Может быть, я могу использовать некоторый Int, сгенерированный в Manifest компилятором?

+0

Вы видели какой-либо вопрос здесь? Я запустил этот код, и он работал, как ожидалось. Вы должны изменить 'erasure' на' runtimeClass' (если используете Scala 2.10', но он работал в обоих направлениях. – cmbaxter

ответ

2

Способ, которым вы его написали, не очень надежный, если у вас более сложная иерархия классов, поскольку, если у вас есть класс D <: C, то classOf[D] != classOf[C]. Таким образом, вы все равно не хотите, чтобы шаблон совпал. Но вы могли; вы не можете назвать classOf[X] в середине модельного матча, но вы можете

def zFor[T <: A : Manifest]: Option[Z] = { 
    val ClassB = classOf[B] 
    val ClassC = classOf[C] 
    manifest[T].erasure match { 
    case ClassB => Some(new Z1) 
    case ClassC => Some(new Z2) 
    case _  => None 
    } 
} 

до тех пор, пока вы уверены, что вы находитесь в ситуации, когда вам нужно только обнаружить листы иерархии классов , (Вы, вероятно, следует убедиться, пометив B и Cfinal.)

В качестве альтернативы, вы можете использовать isAssignableFrom для выполнения теста выполнения:

def zFor2[T <: A : Manifest]: Option[Z] = { 
    manifest[T].erasure match { 
    case x if classOf[B].isAssignableFrom(x) => Some(new Z1) 
    case x if classOf[C].isAssignableFrom(x) => Some(new Z2) 
    case _         => None 
    } 
} 

и теперь

class D extends C(5) {} 

scala> zFor[D] 
res5: Option[Z] = None 

scala> zFor2[D] 
res6: Option[Z] = Some([email protected]) 
1

Я не уверен, если это соответствует вашей проблеме (как вы, вероятно, показали упрощенный пример). Но такая функциональность может быть создана без использования рефлексии.

Это довольно распространенный шаблон, который позволяет создавать дополнительные комбинации без изменения исходного кода.

// the - here allows D to return the instance for C 
// if you only want exact matches, remove the - 
trait GetZ[-X] { 
    type Out 
    def z: Option[Out] 
} 

trait LowerPriority { 
    implicit def noZ[A] = 
    new GetZ[A] { 
     type Out = Nothing 
     val z = None 
    } 
} 

object GetZ extends LowerPriority { 
    implicit def forB = 
    new GetZ[B] { 
     type Out = Z1 
     def z = Some(new Z1) 
    } 

    implicit def forC = 
    new GetZ[C] { 
     type Out = Z2 
     def z = Some(new Z2) 
    } 
} 

def zFor[T](implicit getZ: GetZ[T]): Option[getZ.Out] = getZ.z 

Использование

class D extends C(5) 

val noZ = zFor[A] 
val Some(z1) = zFor[B] 
val Some(z2) = zFor[C] 
val Some(other_z2) = zFor[D] 
Смежные вопросы