LoginSignup
2
0

More than 1 year has passed since last update.

【Kotlin】引数がデフォルト引数か否かを判定する

Last updated at Posted at 2022-06-23

やりたいこと

以下のように、デフォルト引数を設定した関数で、引数が外部から渡されたものか、内部的に設定されているデフォルト引数か判定します。

fun foo(v: Int? = ...)

やり方

以下のようにすればできます。
サンプルコードでは、外部から値を渡した場合その値が、渡さなかった場合defaultが出力されます。
また、Int.MIN_VALUE(= ABSENT_VALUEに設定した値)を渡した場合も正常に判定が行えます。

val ABSENT_VALUE: Int? = Integer.valueOf(Int.MIN_VALUE)

fun foo(v: Int? = ABSENT_VALUE) {
    if (v === ABSENT_VALUE) println("default") else println(v)
}

// -> default
foo()

// -> 1
foo(1)

// -> -2147483648
foo(Int.MIN_VALUE)

原理

Kotlinでは===/!==でインスタンスの比較が行えます。
このため、特定のインスタンスをデフォルト値に設定すると、値が指定されているかのチェックをすることができます。

比較部分(抜粋)
if (v === ABSENT_VALUE) println("default") else println("not default")

ここで、以下2点については注意が必要です。

  • ABSENT_VALUEは確実に固有のインスタンスになるよう指定する
    • 特にプリミティブ型に対するラッパー型などはインスタンスがキャッシュされている場合が有る
  • 引数がプリミティブ型(non-nullIntなど)の場合、この方法は使えない
    • 回避方法は「この値はnullとみなす」ようなマジックナンバーを導入するしか無い

感想

こんなトリッキーなことはしないようにしましょうニッチなテクニックですが、Java向けのライブラリに関連するコードをKotlin化したい時なんかに使えることが有るかなと思います。

追記

Integer型等のインスタンス比較に関する挙動は今後変更の可能性が有るようです。
少なくともJava 18では紹介したコードで成功していましたが、今後成功しなくなる可能性が有ります。

対応方法も考えてみましたが、流石に現実的な感じにはなりませんでした。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0