【问题标题】:Kotlin How to create dynamic ObjectKotlin 如何创建动态对象
【发布时间】:2020-04-24 17:37:59
【问题描述】:

在javascript中我们可以做这样的事情

function putritanjungsari(data){
	console.log(data.name)
}

let data = {
	name:"putri",
	div:"m4th"
}
putritanjungsari(data)

在 kotlin 中,我正在创建一个接受对象作为参数的函数,然后稍后读取它的属性,如何在针对 JVM 的 kotlin 中执行此操作?

【问题讨论】:

  • 虽然这是可能的(例如使用地图),但您应该知道它有许多缺点:它可能比标准属性更慢并且占用更多内存;您会丢失大量编译时检查,从而更容易出现几种类型的错误;您的代码的用户/调用者将无法判断哪些属性可用;继承要困难得多,自定义 getter/setter、质量和比较也是如此……有时需要,但很少需要 IME — 如果您来自动态语言,请确保您不只是这样做,因为它更熟悉。

标签: kotlin


【解决方案1】:

如果我理解你的问题是正确的,你试图有一个变量,将键与某个值或 undefined(null in kt) 相关联,如果没有找到。您正在搜索Map 如果你不知道你想要什么类型,你可以制作一个 Any 类型的地图?所以

Map<String, Any?>

也可以为空

Map<String, Any>

如果你不想为空

您的代码例如:

fun putritanjungsari(data: Map<String, Any?>){
print(data["name"]) 
}

val data: Map<String, Any?> =mapOf(        
"name" to "putri",
"div" to "m4th" 
)
putritanjungsari(data)

请注意,您不能在此处添加新键或编辑任何数据,默认映射是不可变的。还有MutableMap(实现方式相同,只是有放新数据的方法)

【讨论】:

  • 是的,但是因为我希望一切都是动态的,而且我们不知道它的数据类型是什么,所以我认为如果我们像在 JS 中那样使用动态类会更好
  • 在这种情况下,任何地图都会更好
  • 或者任何?如果你想要空值
  • @MatiusNugrohoAryanto 我做了一些修改,检查我的答案以及上面的答案,因为他可能已经明白你的真正意思了
  • 你能举一个我的sn-p的例子吗?
【解决方案2】:

您可以申请property design pattern来解决您的问题。

这是它在 Kotlin 中的实现:

interface DynamicProperty<T> {
    fun cast(value: Any?): T
    fun default(): T

    companion object {
        inline fun <reified T> fromDefaultSupplier(crossinline default: () -> T) =
            object : DynamicProperty<T> {
                override fun cast(value: Any?): T = value as T
                override fun default(): T = default()
            }

        inline operator fun <reified T> invoke(default: T) = fromDefaultSupplier { default }

        inline fun <reified T> required() = fromDefaultSupplier<T> {
            throw IllegalStateException("DynamicProperty isn't initialized")
        }

        inline fun <reified T> nullable() = DynamicProperty<T?>(null)
    }
}

operator fun <T> DynamicProperty<T>.invoke(value: T) = DynamicPropertyValue(this, value)

data class DynamicPropertyValue<T>(val property: DynamicProperty<T>, val value: T)

class DynamicObject(vararg properties: DynamicPropertyValue<*>) {
    private val properties = HashMap<DynamicProperty<*>, Any?>().apply {
        properties.forEach { put(it.property, it.value) }
    }

    operator fun <T> get(property: DynamicProperty<T>) =
        if (properties.containsKey(property)) property.cast(properties[property])
        else property.default()

    operator fun <T> set(property: DynamicProperty<T>, value: T) = properties.put(property, value)
    operator fun <T> DynamicProperty<T>.minus(value: T) = set(this, value)
}

fun dynamicObj(init: DynamicObject.() -> Unit) = DynamicObject().apply(init)

您可以通过以下方式定义您的属性:

val NAME = DynamicProperty.required<String>() // throws exceptions on usage before initialization
val DIV = DynamicProperty.nullable<String>() // has nullable type String?
val IS_ENABLED = DynamicProperty(true) // true by default

现在你可以使用它们了:

fun printObjName(obj: DynamicObject) {
    println(obj[NAME])
}

val data = dynamicObj {
    NAME - "putri"
    DIV - "m4th"
}
printObjName(data)

// throws exception because name isn't initialized
printObjName(DynamicObject(DIV("m4th"), IS_ENABLED(false)))

使用DynamicObject 而不是Map&lt;String, Any?&gt; 的原因:

  1. 类型安全(NAME - 3NAME(true) 不会编译)
  2. 属性使用不需要强制转换
  3. 您可以定义当属性未初始化时程序应执行的操作

【讨论】:

    【解决方案3】:

    你必须使用Any,然后你必须像这样投射你的对象

    private fun putritanjungsari(data : Any){
        if(data is Mydata){
            var data =  data as? Mydata
            data.name
        }
    }
    

    【讨论】:

    • 似乎最接近的方法,如何知道数据从哪里继承,或者数据是什么类型的实例
    • 您正在使用不同的对象调用此函数,然后您知道我正在使用所有对象调用此函数,因此您可以区分所有对象并找到该对象的所有成员
    【解决方案4】:

    Kotlin 是静态类型语言,因此它需要精确定义或明确推断的参数类型(例如,Groovy 至少通过两种方式解决了这种情况)。但是对于 JS 互操作性,Kotlin 提供了dynamic type

    同时,在您的特定情况下,您可以将 data 结构键入到 kt 的 Map 中,并且不要与严格的类型争论。

    【讨论】:

      【解决方案5】:

      只是为了灵感。在 Kotlin 中,您可以创建临时对象:

      val adHoc = object {
          var x = 1
          var y = 2
      }
      println(adHoc.x + adHoc.y)
      

      【讨论】:

      • 这仅适用于本地和私有范围
      猜你喜欢
      • 2021-08-13
      • 2011-04-29
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 2012-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多