Kotlin принудительное использование типа аргумента: String, Boolean или Number - PullRequest
2 голосов
/ 07 апреля 2020

У меня есть сценарий использования, когда я отправляю некоторые данные на свой сервер (в качестве аналитики), которые всегда либо String, Boolean или Number.

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

Следующие случаи должны работать -

userProperties: MutableMap<String, in AnyPrimitive> = mutableMapOf(),

userProperties.put("someKey", 1)
userProperties.put("someKey", 1.2f)
userProperties.put("someKey", "someValue")
userProperties.put("someKey", true)

, но не

userProperties.put("someKey", myCustomObjectInstance)

Подход, который я пробовал, создавал реферат класс EventData, который реализует CharSequence и Number. Но для этого требуется, чтобы каждый создал экземпляр этого класса, а не отправлял просто число или строку.

Я могу поставить logi c для проверки типа и выбросить исключение, но я бы предпочел ограничить его при компиляции время.

Ответы [ 4 ]

0 голосов
/ 07 апреля 2020

Мое лучшее предложение - что-то вроде этого:

sealed class Data {
    class StringData(val s: String): Data()
    class NumberData(val n: Int): Data()
    class BooleanData(val b: Boolean): Data()
    companion object {
        fun of(s: String) = StringData(s)
        fun of(n: Int) = NumberData(n)
        fun of(b: Boolean) = BooleanData(b)
    }
}

Тогда ваш фрагмент становится следующим:

userProperties: MutableMap<String, Data> = mutableMapOf(),

userProperties.put("someKey", Data.of(1))
userProperties.put("someKey", Data.of("someValue"))
userProperties.put("someKey", Data.of(true))

В какой степени это возможно, действительно зависит от остальной части вашего кода.

0 голосов
/ 07 апреля 2020

Три перегрузки согласно комментарию al3 c. Невозможно достичь того, что вы указываете с помощью обобщений в kotlin.

fun send(arg: Number) {
    // send
}

fun send(arg: Boolean) {
    // send
}

fun send(arg: String) {
    // send
}

// Many properties gathered in map described below
fun send(arg: EventData) {
    // send
}

Если вы хотите использовать объект карты для отправки аналитики. Для этого нужен новый класс, содержащий три вышеуказанные перегрузки. Чтобы запретить пользователю этого класса добавлять что-либо не того класса.

class EventData {

    // Or depending on other requirements you could use three maps with specific type
    private val analyticsData = mutableMapOf<String, Any>()

    fun put(key: String, arg: Number) {
         analyticsData.put(key, arg)
    }

    fun put(key: String, arg: Boolean) {
         analyticsData.put(key, arg)
    }

    fun put(key: String, arg: String) {
         analyticsData.put(key, arg)
    }

}
0 голосов
/ 07 апреля 2020

Это должно было прийти мне в голову раньше. Я могу написать собственный процессор аннотаций и аннотаций, который будет проверять тип параметра во время компиляции. Примерно так:

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface SupportedTypes {

  Class<?>[] types() default {};
}

И написать собственный процессор аннотаций, который будет проверять типы всех элементов, переданных в types().

. Я буду обновлять ответ, когда буду писать пользовательский. процессор аннотаций. Между тем можно сослаться Как написать собственный процессор аннотаций

0 голосов
/ 07 апреля 2020

Если вы хотите упростить с точки зрения использования, объявите функцию отправки следующим образом:

fun send(arg: Any) {
    //Validations here:
    if (!validate(arg)) throw IllegalArgumentException("...")

    //Actual send code here...
}

private fun validate(arg: Any): Boolean {
    return (arg is String || arg is Boolean || arg is Number)
}

Обратите внимание, что это не применяется во время компиляции, но является ошибкой во время выполнения. Поэтому, если кто-то закодирует

send(RandomObject)

, компиляция будет успешной. Хотя во время выполнения это не удастся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...