我有一个用例,我将一些数据发送到我的服务器(作为分析(,该服务器始终是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)
我尝试的方法是创建一个实现CharSequence
和Number
的抽象类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()
中传递的所有项的类型。
当我编写自定义注释处理器时,我将对答案进行猜测。同时你可以参考如何编写自定义注释处理器