技術関係

Kotlinでもやっぱりジェネリクスの関数オーバーロードは出来ない

Kotlinで引数にジェネリクスを取る関数のオーバーロードを実装してみようと思ったときに詰まったのでメモ。

こんな感じで作ってみるとエラーが出る。

fun main() {
	class Moge {
		fun plusMoge(stringList: List<String>) {
			plusMoge(listOf(stringList.map { it.toInt() }))
		}

		fun plusMoge(intList: List<Int>) {
			intList.forEach { println(it + 1) }
		}
	}

	val moge = Moge()
	moge.plusMoge(listOf("1"))
}

Platform declaration clash: The following declarations have the same JVM signature

とエラーが出てそもそもコンパイル出来ない。

こんなエラー。

スポンサーリンク

関数のオーバーロードは型情報が消えるので出来ない

どうやらジェネリクスはコンパイル時に型情報が消去される仕様が起因していてオーバーロード出来ない。

Java ジェネリクスのポイント # コンパイル時に型情報は消去される / Qiita @pebblip

OK: 片方のジェネリクスを取る引数をなくす

無理やり実験。
片一方のplusMoge()の引数をList<Int>からIntに変えてジェネリクスを取らない引数にしてみる。

そうすれば型情報がコンパイラに消されても当然呼び出し側から区別が付くのでコンパイル出来る。
普通の関数オーバーロード。

fun main() {
	class Moge {
		fun plusMoge(stringList: List<String>) {
			stringList.forEach { plusMoge(it.toInt()) }
		}

		fun plusMoge(int: Int) {
			println(int + 1)
		}
	}

	val moge = Moge()
	moge.plusMoge(listOf("1"))
}

気になったので一応でコンパイルしてみる。

final class Moge {
	public final void plusMoge(@NotNull List stringList) {
		Intrinsics.checkNotNullParameter(stringList, "stringList");
		Iterable $this$forEach$iv = (Iterable)stringList;
		int $i$f$forEach = false;
		Iterator var4 = $this$forEach$iv.iterator();

		while(var4.hasNext()) {
			Object element$iv = var4.next();
			String it = (String)element$iv;
			int var7 = false;
			boolean var9 = false;
			this.plusMoge(Integer.parseInt(it));
		}

	}

	public final void plusMoge(int var1) {
		int var2 = var1 + 1;
		boolean var3 = false;
		System.out.println(var2);
	}

	public Moge() {
	}
}

Moge moge = new Moge();
moge.plusMoge(CollectionsKt.listOf("1"));

現実的な解決策: 諦めて別の関数を作る

関数のオーバーロードは諦めて別々で関数に命名する。

潔くて一番早い。無理にオーバーロードしなくてもいいなら諦めた方が良さそう。

fun main() {
	class Moge {
		fun plusMogeForString(stringList: List<String>) {
			plusMoge(listOf(stringList.map { it.toInt() }))
		}

		fun plusMogeForInt(intList: List<Int>) {
			intList.forEach { println(it + 1) }
		}
	}

	val moge = Moge()
	moge.plusMogeForString(listOf("1"))
        moge.plusMogeForInt(listOf(1))
}

環境

Kotlin v1.5.21

参考

Javaのジェネリクスの注意点 / HACK NOTE

Java ジェネリクスのポイント / Qiita @pebblip

コメント

タイトルとURLをコピーしました