2016-02-21 3 views
2
abstract class Handler { 
    type Message 

    def handleAny(msg: Any) { 
    if (msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message]) // fix me! 
    } 

    def handle(msg: Message) 
} 

class StringHandler extends Handler { 
    override type Message = String 

    def handle(msg: Message) { println(s"handling: $msg") } 
} 

val h = new StringHandler 
h.handleAny("ahoj") 
h.handleAny(true) 

warning: abstract type Handler.this.Message is unchecked since it is 
eliminated by erasure 
       if(msg.isInstanceOf[Message]) handle(msg.asInstanceOf[Message]) 
           ^
one warning found 
handling: ahoj 
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.String 
     at Main$$anon$1$StringHandler.handle(typeProblem.scala:11) 
     at Main$$anon$1$Handler.handleAny(typeProblem.scala:5) 

Как изменить фрагмент (без изменения интерфейса или замены поле типа с параметром типа), чтобы работать, как и ожидалось, что обрабатывать только те сообщения, заданных опциями тип поля?Стирание полей типа

Я ищу решение, которое может быть применено к родительскому абстрактному классу, а не загрязнению всех детей.

Я также попытался использовать match, и он ведет себя точно так же. Или это невозможно сделать с полями типа (я думал, что они более мощные, чем параметры типа)?

ответ

2

Обычно используется совпадение и в вашем случае, так как вы не хотите добавлять какие-либо параметры типа, вам нужно будет указать ClassTag (я думаю).

Что-то вдоль линий:

import scala.reflect.ClassTag 

abstract class Handler { 
    type Message <: Any 
    implicit val tag: ClassTag[Message] 

    def handleAny(msg: Any): Unit = { 
    msg match { 
     case tag(message) => 
     handle(message) 
     case _ => 
     throw new IllegalArgumentException(s"Argmument MUST BE a 'Message' but $msg is not!") 
    } 
    } 

    def handle(msg: Message): Unit 
} 

object StringHandler extends Handler { 
    override type Message = String 
    // lazy is important here! 
    implicit lazy val tag: ClassTag[Message] = ClassTag(classOf[String]) 

    def handle(msg: Message): Unit = { println(s"handling: $msg") } 
} 


StringHandler.handleAny("ahoj") 
StringHandler.handleAny(true) 
Смежные вопросы