2011-01-15 5 views
4

Я написал пару функций, которые выглядят так:Дать обобщенную функцию, которая может принять Writer, а также в OutputStream

def myWrite(os: OutputStream) = {} 
def myWrite(w: Writer) = {} 

Теперь оба очень похожи, и я думал, что я хотел бы попробовать написать один параметризованная версия функции.

Я начал с типа с двумя методами, которые являются общими в Java OutputStream и Writer:

type Writable[T] = { 
    def close() : Unit 
    def write(cbuf: Array[T], off: Int, len: Int): Unit 
} 

Одна проблема в том, что OutputStream пишет Byte и писатель пишет Char, так что я параметризованных типа с T.

Тогда я пишу функцию:

def myWrite[T, A[T] <: Writable[T]](out: A[T]) = {} 

и попытаться использовать его:

val w = new java.io.StringWriter() 
myWrite(w)       

Результат:

<console>:9: error: type mismatch; 
found : java.io.StringWriter 
required: ?A[ ?T ] 
Note that implicit conversions are not applicable because they are ambiguous: 
both method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] 
and method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] 
are possible conversion functions from java.io.StringWriter to ?A[ ?T ] 
     myWrite(w) 

Я попробовал несколько других комбинаций типов и параметров, пока не помогло.

Мой вопрос заключается в том, есть ли способ достичь этого вообще, и если да, то каким образом.

(Обратите внимание, что реализация myWrite потребуется, внутренне, чтобы знать тип T, параметризующее метод записи(), потому что он должен создать буфер, как в новом ArrayT.)

ОБНОВЛЕНИЕ: " правильное»решение не работает, потому что ошибка в компиляторе: https://lampsvn.epfl.ch/trac/scala/ticket/2672

ответ

0

Это работает:

myWrite(w.asInstanceOf[Writable[Char]]) 

... так что вы думаете, что это будет работать:

implicit def wrToWr(w:java.io.Writer): Writable[Char] = w.asInstanceOf[Writable[Char]] 

... но это не так. Я не знаю, почему нет:

scala> myWrite(w) 
<console>:17: error: type mismatch; 
found : java.io.StringWriter 
required: Nothing 
     myWrite(w) 
      ^

Куда ничто не приходит?

+0

Вам не нужно заставлять литье использовать 'asInstanceOf'; простой 'myWrite (w: Writable [Char])' должен делать трюк, так как формально 'Writable [Char]' действует как суперкласс «Writer» с учетом определений типов. Кроме того, 'Nothing' происходит от механизма вывода типов с использованием наиболее конкретного типа. 'Nothing 'является подклассом для каждого другого класса, поэтому он использует это, если он не вынужден делать иначе (и он не понимает, что он вынужден делать иначе, он считает, что он может разрешить' T' независимо от 'A'). –

+0

А, это многое объясняет. Благодарю. –

1

Прежде всего, вам не нужно параметризовать A в myWrite. Ваши целевые классы не являются общими! Во-вторых, вам не нужно явно разрешать подклассы - просто дайте наследованию сделать трюк для вас.

def myWrite[T](out: Writable[T]) = {} 

Теперь метод может вызывать тип T. До тех пор, пока вы не по какой-то причине нужно истинный тип A также, что это будет работать для вас:

myWrite(new StringWriter) 

Однако, вы собираетесь столкнуться с проблемой:

def myWrite[T](out: Writable[T]) = new Array[T](0) // Doesn't work! 

Проблема в том, что это общий код.Он не знает, что такое T - это может быть что угодно! Таким образом, вы должны сообщить компилятору передать информацию, которая идентифицирует T:

def myWrite[T : ClassManifest](out: Writable[T]) = new Array[T](0) 

(Edit:. Упростили ответ, чтобы сделать это на самом деле работает)


(Edit: на самом деле, это Безразлично» t достаточно работать - см. комментарии.)

+0

Это все еще не работает: я получаю аргументы 'error: inferred type [Nothing, java.io.FileWriter] не соответствуют методу метода myWrite. [T, A <: Writable [T]]'! – ebruchez

+0

BTW, когда вы говорите «он не знает, что такое« T »: как я человек, я могу отличить тип: я замечаю, что Writer соответствует моему Writable, который, как оказалось, имеет метод write() с массивом [ Char]. Итак, теперь я знаю, что у меня есть Writable [Char]. Кажется, что, по крайней мере, в таком случае система типов должна иметь возможность вывести T. Я не знаю, как система типов работает глубоко, и если такой вывод совместим или нет, но как человек I может определенно сделать вывод. Во всяком случае, было бы здорово, если бы это сработало из коробки, на данный момент я могу согласиться с имплицитами, если их можно заставить работать! – ebruchez

+0

Есть сложный способ и простой способ исправить проблему в моем оригинальном посте (у меня было слишком много неявного материала в REPL сразу и смутило, почему все работает). Я пошел на простой путь, которого, вероятно, достаточно. Вы можете добавить другую оболочку, чтобы сделать это сложным способом, если вам нужен фактический тип 'A' вместо его суперкласса' Writable [Char] 'или' Writable [Byte] '. –

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