Kotlin强制参数类型为String、Boolean或Number



我有一个用例,我将一些数据发送到我的服务器(作为分析(,该服务器始终是StringBooleanNumber

如何强制调用方只发送数字、布尔值或字符串,而不发送任何其他对象?

以下情况应该有效-

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)

我尝试的方法是创建一个实现CharSequenceNumber的抽象类EventData。但这需要每个人都创建这些类的实例,而不是简单地发送一个数字或字符串。

我可以放置一个逻辑来检查类型并抛出异常,但我更喜欢在编译时限制它。

我最好的建议是这样的:

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))

这在多大程度上可行实际上取决于代码的其余部分。

如果您想从使用角度进行简化,请声明send函数如下:

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)

编译将成功。不过在运行时它会失败。

根据al3c的注释有三个重载。没有办法实现您在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)
}
}

我应该早点想到。我可以编写自定义注释和注释处理器,它将在编译时检查参数的类型。类似这样的东西-

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface SupportedTypes {
Class<?>[] types() default {};
}

并编写一个自定义注释处理器,用于检查types()中传递的所有项的类型。

当我编写自定义注释处理器时,我将对答案进行猜测。同时你可以参考如何编写自定义注释处理器

相关内容

最新更新