kotlin: общий для разных типов

Мне нужны линейные функции:

class Linear(val a : Double, val b : Double) { fun eval(in : Double) { return a*in + b } } 

Тогда мне нужно то же самое для векторов.

 class Vector3d(val a1 : Double, val a2 : Double, val a3 : Double) { // use operator overloading https://kotlinlang.org/docs/reference/operator-overloading.html to make +, -, /, *, etc. possible for vectors } class Linear(val a : Vector3d, val b : Vector3d) { fun eval(in : Vector3d) { return a*in + b } } 

Как вы можете видеть, два линейных класса идентичны (за исключением типов аргументов). Теперь я не могу сделать общий класс, поскольку Double и Vector3d не имеют общего суперкласса.

Если я хочу написать Linear только один раз, единственным вариантом является мой собственный Double-type, который имеет общий интерфейс с Vector3d. Однако это означает, что я больше не могу использовать 0 в исходном коде, но я должен использовать MyDouble (0) всюду. Я мог бы перегрузить конструктор Linear, чтобы принимать двойники, и создать объекты MyDouble внутри, однако мне нужно будет сделать это для каждого отдельного метода в моем API.

Есть ли лучшее решение?

Вы можете ввести уровень косвенности, указав интерфейс / класс, который имеет две реализации / подклассы: один для примитивных двойников и один для вашего Vector3d . Однако вы можете найти накладные расходы нежелательными. например:

 interface Arithmetical<A : Arithmetical<A>> { operator fun plus(other: A): A operator fun minus(other: A): A operator fun times(other: A): A operator fun div(other: A): A } class Linear<A : Arithmetical<A>>(val a: A, val b: A) { fun eval(`in`: A): A { return a * `in` + b } } class ArithmeticalDouble(val value: Double) : Arithmetical<ArithmeticalDouble> { override fun plus(other: ArithmeticalDouble) = ArithmeticalDouble(value + other.value) override fun minus(other: ArithmeticalDouble) = ArithmeticalDouble(value - other.value) override fun times(other: ArithmeticalDouble) = ArithmeticalDouble(value * other.value) override fun div(other: ArithmeticalDouble) = ArithmeticalDouble(value / other.value) } class Vector3d(val a1: Double, val a2: Double, val a3: Double) : Arithmetical<Vector3d> { override fun plus(other: Vector3d): Vector3d = TODO() override fun minus(other: Vector3d): Vector3d = TODO() override fun times(other: Vector3d): Vector3d = TODO() override fun div(other: Vector3d): Vector3d = TODO() } 

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

Фактически, вы технически можете создать класс с использованием дженериков, но класс не будет знать, как умножить T на T, поскольку он является подклассом Any , а Any не поддерживает этот операнд. Через smart-casts вы можете оценить, что такое T:

 class Linear<T>(val a: T, val b: T) { fun eval(c: T): Any { when { a is Double -> return a * c as Double + b as Double a is Double -> return a * c as Vector3d + b as Vector3d else -> return Unit } } 

Дополнительную информацию см. В общих документах на Kotlin-docs.

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

Другой альтернативой было бы использовать Number (или Double ) как суперкласс для Vector3d и реализовать методы как длину. Это также не было бы хорошей практикой, но по крайней мере вы могли бы использовать <Number> как generics.

Intereting Posts
Почему этот ChildEventListener не считывает данные с узла firebase? Могу ли я использовать Kotlin с Codename One? Побитовая операция «и» в котлин Объединение данных из разных Observables и выбор различных стратегий получения, в зависимости от доступности данных Вызовите конструктор по умолчанию из другого в Kotlin Kotlin: Как получить группу захвата первой строки, которая соответствует? Есть ли простой способ увидеть, какие исключения выбрала функция Котлина? Android Studio 3.0 не может предложить импорт для shl и shr в Kotlin Как проверить функцию kotlin varargs с помощью mockito Значения по умолчанию с помощью @ProjectedPayload / ProjectingJackson2HttpMessageConverter Неразрешенная ссылка: LinearLayoutManager / RecyclerView Быстрое наследование объектов и значение интерфейса Где поставить сгенерированный источник java или kotlin при создании плагина gradle? Что представляет собой редакторский редактор для Kotlin Android Extensions for Views? Неверное «это» используется в гнездовых замыканиях