2015-12-15 3 views
0

Я смущен тем, как работают ограничения в генераторах Scala. Рассмотрим следующий пример:Scala generics: почему два типа с одинаковой верхней границей несовместимы?

sealed trait MessageBody 
    case class Body1() extends MessageBody 
    case class Body2() extends MessageBody 
    sealed trait MessageKey[T <: MessageBody] 
    case object Key1 extends MessageKey[Body1] 
    case object Key2 extends MessageKey[Body2] 

    type MessageHandler[B <: MessageBody] = PartialFunction[MessageKey[B], B => Unit] 

    abstract class Handler { 
    def messageHandler[B <: MessageBody]: MessageHandler[B] 
    } 

    class ProcessingHandler[ReturnType <: MessageBody](val onSuccess: MessageKey[ReturnType]) extends Handler { 
    override def messageHandler[B <: MessageBody]: MessageHandler[B] = { 
     case `onSuccess` => success 
    } 
    def success(msg: ReturnType): Unit = println(msg) 
    } 

Это дает мне ошибку:

error: type mismatch; 
found : ReturnType => Unit 
required: B => Unit 
      case `onSuccess` => success 
           ^

В моем наивном понимании, как ReturnType и B являются подтипы MessageBody и, следовательно, должны быть совместимы. Почему они не совместимы и как мне написать свой код, чтобы сделать их совместимыми?


EDIT: Следующий фрагмент кода работает нормально, и если я смешиваю связь между MessageKey и MessageBody экземпляров в любом месте, я получаю хорошую ошибку во время компиляции.

class ProcessingHandler2 extends Handler { 
    override def messageHandler[B <: MessageBody]: MessageHandler[B] = { 
    case Key1 => h1 
    // case Key1 => h2 // gives compile-time error 
    case Key2 => h2 
    } 
    def h1(x: Body1): Unit = println(x) 
    def h2(x: Body2): Unit = println(x) 
} 

    val handler: Handler = new ProcessingHandler2 
    handler.messageHandler(Key1)(Body1())    
    // handler.messageHandler(Key1)(Body2()) // gives compile-time error 

EDIT: Очевидно, что нет никакого способа компиляции проверить это: handler.messageHandler(Key3), и это приведет к MatchError во время выполнения.

ответ

2

Предположим, у вас есть объект типа ProcessingHandler[Body1], а затем позвоните по телефону messageHandler[Body2]. Согласно подписи, он должен вернуть Body2 => Unit, но вы попытаетесь вернуть Body1 => Unit. Если вы пытались вернуть MessageBody => Unit, это было бы нормально, так как MessageBody является суперклассом Body2, но Body1 нет. Они оба являются детьми одного и того же суперкласса, но это не делает их совместимыми, то есть вы не можете передать Body2 в качестве аргумента функции, которая принимает Body1 или наоборот.

В зависимости от того, что именно ваши требования, есть несколько вещей, которые вы могли бы сделать:

Вы могли бы сделать Handler родовое вместо messageHandler, а затем продлить Handler[ReturnType] (или вы могли бы дать Handler тип элемента и использовать его в messageHandler).

Или вы могли бы сделать success в качестве аргумента вместо ReturnType.

+0

В случае, если я вызываю 'messageHandler [Body2]' на объект типа 'ProcessingHandler [Body1]' Я ожидаю ошибку времени компиляции. По той же причине я не могу заставить 'success' взять' MessageBody', потому что тогда я теряю безопасность статического типа. И я не могу создать «Handler» generic, потому что он также имеет другие подклассы, которые имеют много методов обработчика сообщений с различными сигнатурами. – Mahdi

+0

@Mahdi Это не то, как работают дженерики, и это не будет действительной реализацией интерфейса. В вашем интерфейсе говорится, что «метод« messageHandler »принимает параметр типа, который должен быть подклассом« MessageBody ». Поэтому, если у вас есть реализация этого интерфейса, и вы вызываете его с параметром типа, который является подклассом «MessageBody», нет никакой возможной причины, почему он не должен компилироваться. Проблема в том, что ваша реализация интерфейса делает то, что работает только с определенными параметрами типа. Это ошибка в реализации, а не использование метода. – sepp2k

+0

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

Смежные вопросы