次のようなkotlin関数を想定します。
fun f(p1: T1? = null, p2: T2? = null, ..., pN: TN? = null) {
// ...
}
上記の関数の実装は、最初の呼び出しがp1 = null
を暗黙的に渡し、2番目の呼び出しが明示的に渡した次の2つの呼び出しを区別できますか?
f() // Implicit
f(null) // Explicit
f(p1 = null) // Explicit
注:任意の数のパラメーターが存在する可能性があります
本番環境ではこのアプローチを使用しませんが、次のスニペットで行ったようなことができます。
_object Default {
val defaultMapping = mutableMapOf<KClass<*>, Any?>()
inline fun <reified T> get(): T? =
T::class.let {
defaultMapping[it] ?: it.Java.constructors.getOrNull(0)?.let { c ->
try {
// NOTE: for now only parameterles constructor will work
c.newInstance()
} catch (e: Exception) {
e.printStackTrace()
null
}.also { v ->
defaultMapping[it] = v
}
} ?: run {
defaultMapping[it] = null
null
}
} as? T
inline fun <reified T> T.isDefault(): Boolean = defaultMapping[T::class] == this
}
inline fun <reified T> foo(bar: T? = Default.get()) {
if (bar?.isDefault() == true) println("bar: default is in use")
else println("bar: $bar")
}
fun main() {
foo<Any>()
foo(Default.get<Any>())
foo<Any>(null)
foo<Any>(bar = null)
foo(Any())
val a = Any()
foo(a)
foo(bar = a)
}
_
注意してください、私はコードをいかなる方法でも洗練していません。一部の部分はいくつかの試みの残り物です(たとえば、constructors.getOrNull(0)
に関する部分)。私はそれを改善するつもりはありません。
また、この単純なアプローチは、JVMのデフォルトのコンストラクター(it.newInstance()
を参照)でのみ機能します。ですから、それは決してマルチプラットフォームのソリューションではありません。
結果は次のようなものです
_bar: default is in use
bar: default is in use
bar: null
bar: null
bar: Java.lang.Object@41906a77
bar: Java.lang.Object@4b9af9a9
bar: Java.lang.Object@4b9af9a9
_
繰り返しますが、これは非常に単純化されているため、本番環境では使用しないでください!