Статические свойства из общих параметров в Котлине

#kotlin

Вопрос:

Вопрос:

  1. Как я могу конкретизировать object типы, если они указаны в качестве общего параметра
  2. Или Как я могу реализовать статические свойства в Kotlin?

Я знаю, что самое близкое, что у нас есть к статическим данным, — это использование object .

Простой Пример

Наличие интерфейса, который будет реализован только объектами

 interface SomeObject {
    val someProperty: String
}

object AnObject: SomeObject {
    override val someProperty = "someValue"
}
 

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

 class GenericClass<O: SomeObject> { 

    var someValue: String
        get() = O.someProperty   // This is not possible
}

GenericClass<AnObject>().someValue
 

Единственным способом было бы также передать объект в качестве параметра конструктора

 class GenericClass<O: SomeObject>(
    val obj: O
) { 
    var someValue: String
        get() = obj.someProperty
}

GenericClass(AnObject).someValue
 

Повторяя вопрос выше

  1. Есть ли способ овеществить этот объект?
  2. Или есть ли какой-либо другой способ реализации статических свойств типов?

Комментарии:

1. Я думаю, у вас может быть встроенная фабричная функция, которая создает GenericClass<O> объекты… Тот, который создает исключение, если objectInstance значение равно null. Тебе это нравится?

2. Я вижу, что статический let swift не несет бремени JVM, и у меня сложилось впечатление, что это сложно для JVM из-за стирания общего типа, но я могу ошибаться. У меня все равно была бы фабрика для создания универсальных объектов, чтобы иметь больше контроля, но не сидя перед проблемой, я просто еще один id10t за клавиатурой 🙂 (и с проблемой я все еще id10t за клавиатурой, но с проблемой, которую нужно решить впереди) 🙂

3. В комментариях вы сказали: «Объекты, которые будут переданы в нее, будут предоставлены этой библиотекой». В этом случае вы можете пометить интерфейс как закрытый интерфейс. Запечатанный интерфейс гарантирует, что пользователям придется выбирать одну из ваших реализаций, которые все являются объектами, поэтому у них нет конструкторов. В качестве альтернативы вы можете использовать класс перечисления, где у каждого члена класса есть одна из ваших реализаций.

4. В качестве альтернативного способа использования отражения вы можете создать макет конструктора для своего универсального класса в сопутствующем объекте с помощью inline operator fun <reified T: SomeObject> invoke(): GenericClass<T> = GenericClass(T::class.objectInstance ?: error("unsupported type")) . Если это закрытый интерфейс, вы знаете, что он безопасен от получения типа без связанного объекта. Если только в качестве типа не указан сам интерфейс SomeObject. Вы можете указать поведение по умолчанию вместо того, чтобы бросать, если хотите.

5. @MartinMarconcini Да, я понимаю. Заводской метод с овеществлением и ошибками, по-видимому, является лучшим подходом на данный момент. Спасибо за поддержку товарища id10t 🙂

Ответ №1:

Одним из способов овеществления объекта является использование отражения:

 inline fun <reified T> getObject(): T? = T::class.objectInstance
 

Если вы действительно уверены, что универсальный тип будет объектом

 inline fun <reified T> getObject(): T = T::class.objectInstance ?: error("Not an object!")
 

Это может быть использовано в конструкторе макета для GenericClass

 class GenericClass private constructor(private val obj: O) {

    var someValue: String
        get() = obj.someProperty

    companion object {
        inline operator fun <reified T: SomeObject> invoke(): GenericClass<T> = 
            GenericClass(T::class.objectInstance ?: error("unsupported type"))
    }
}
 

И может быть вызван по желанию, используя только общий параметр

 GenericClass<AnObject>().someValue