2016-02-23 5 views
4

Я пытаюсь создать очень простой общий класс NDArray в Котлине, который принимает выражение лямбда как функцию init.Kotlin NDArray с конструктором лямбда с общим типом возврата

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) { 
    val values: Array<T> = Array(i * j, f) 
} 

Типичное использование будет:

fun main(args: Array<String>){ 
    val m = NDArray(4, 4, ::zero) 
} 

fun zero(i: Int) = 0.0 

Моя проблема заключается в том, что компилятор Котлин жалуется на инициализации значений в конструкторе

values = Array(i * j, f) 

, говоря: «Не удается использовать«T 'в качестве параметра типа reified. Вместо этого используйте класс. Зачем ?

EDIT:

Если я вместо этого заменить реализацию массива Котлин с моим собственным MyArray компилирует:

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) { 
    val values: MyArray<T> = MyArray(i * j, f) 
} 

class MyArray<T>(i:Int, init: (Int) -> T) { 
    ... 
} 

Не знаю, почему Котлин лечит MyArray отличается от обычного массива, когда оба имеют одинаковый конструктор?

+0

почему не просто класс 'NDArray (я: Int, J: Int, F: (Int) -> T) { значения знач: Array = Массив (я * J, f) } '? – voddan

+0

Определенно более кратким, но проблема все еще сохраняется, поскольку массив должен иметь тип T, а не Int. –

+1

Неидиоматический код Котлина трудно читать. См. Edit – voddan

ответ

4

Для создания массива Java требуется указать тип элемента. В случае вашего класса тип элемента предоставляется только как параметр типа класса, а генерики в Java стираются во время выполнения. Из-за этого тип элемента массива неизвестен, и его невозможно создать.

Если вы хотите создать пользовательскую оболочку вокруг стандартного Array<T>, она должна была бы выглядеть следующим образом:

class NDArray<reified T>(i:Int, j:Int, init: (Int) -> T) { 
    val arr = Array<T>(i * j, init) 
} 

reified ключевое слово означает, что ваш T не стирается, и может быть использовано в тех местах, где необходим реальный класс, например, вызов конструктора Array().

Обратите внимание, что этот синтаксис не поддерживается для класса конструкторов, но это все равно полезно для заводских функций (должен быть inline d)

fun <reified T> arrayFactory(i:Int, j:Int, init: (Int) -> T) = Array<T>(i * j, init) 
+0

Понял, что ему было что-то делать с стиранием типа. Если вы посмотрите на него с точки зрения JVM, я вижу проблему создания массива родового типа T [] во время выполнения. С точки зрения Котлина я еще немного озадачен, см. Править. –

+0

В принципе, упаковка Array () невозможна без использования заводского шаблона? Btw, см. Edit –

0

на основе входных данных из Yole и voddan это лучшее решение Я нашел к этой проблеме до сих пор:

class NDArray<T>(val values: Array<T>){ 

    companion object Factory{ 
     inline operator fun <reified T>invoke(i: Int, j: Int, noinline init: (Int) -> T) = NDArray(Array(i * j,init)) 
    } 
} 

Это позволяет использовать овеществленная в качестве конструктора, используя объект-компаньон. Соглашение о создании здания может быть выполнено с использованием оператора invoke. Это работает сейчас:

fun main(args: Array<String>){ 
    val m = NDArray(4,4, ::zero) 
} 

fun zero(i:Int) = 0.0 

Единственная проблема (для запутанного синтаксиса Invoke, кроме()) является то, что конструктор NDArray должен быть публичным. Возможно, есть лучший способ?

ПРИМЕЧАНИЕ! После проблем KT-11182 аффекты этот шаблон дизайна

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