나는이 기능이 작동 이유를 알고 싶어 자바 도에서 코 틀린 에 tailrec
있지만에서 코 틀린 없이 tailrec
?
짧은 답변은 Kotlin 방법이 JAVA 방법보다 "무겁기"때문 입니다. 모든 호출에서 "provokes"라는 다른 메소드를 호출합니다 StackOverflowError
. 아래에서 더 자세한 설명을 참조하십시오.
에 대한 Java 바이트 코드 reverseString()
Kotlin 및 JAVA 의 메소드에 대한 바이트 코드를 그에 따라 확인했습니다.
자바의 코 틀린 메소드 바이트 코드
...
public final void reverseString(@NotNull char[] s) {
Intrinsics.checkParameterIsNotNull(s, "s");
this.helper(0, ArraysKt.getLastIndex(s), s);
}
public final void helper(int i, int j, @NotNull char[] s) {
Intrinsics.checkParameterIsNotNull(s, "s");
if (i < j) {
char t = s[j];
s[j] = s[i];
s[i] = t;
this.helper(i + 1, j - 1, s);
}
}
...
자바의 자바 메소드 바이트 코드
...
public void reverseString(char[] s) {
this.helper(s, 0, s.length - 1);
}
public void helper(char[] s, int left, int right) {
if (left < right) {
char temp = s[left];
s[left++] = s[right];
s[right--] = temp;
this.helper(left, right, s);
}
}
...
따라서 두 가지 주요 차이점이 있습니다.
Intrinsics.checkParameterIsNotNull(s, "s")
Kotlin 버전 helper()
에서 각각 호출됩니다 .
- JAVA 메소드의 왼쪽 및 오른쪽 인덱스 가 증가하는 반면 Kotlin 에서는 각 재귀 호출에 대해 새 인덱스가 작성됩니다.
Intrinsics.checkParameterIsNotNull(s, "s")
혼자 행동에 어떤 영향을 미치는지 테스트 해 봅시다 .
두 가지 구현 모두 테스트
두 경우 모두에 대한 간단한 테스트를 만들었습니다.
@Test
public void testJavaImplementation() {
char[] chars = new char[20000];
new Example().reverseString(chars);
}
과
@Test
fun testKotlinImplementation() {
val chars = CharArray(20000)
Example().reverseString(chars)
}
들어 JAVA 에 대한 동안 테스트가 문제없이 성공 코 틀린 이 때문에에 비참하게 실패 StackOverflowError
. 내가 추가 한 후 그러나 Intrinsics.checkParameterIsNotNull(s, "s")
받는 자바 방법 그것은뿐만 아니라 실패
public void helper(char[] s, int left, int right) {
Intrinsics.checkParameterIsNotNull(s, "s"); // add the same call here
if (left >= right) return;
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
helper(s, left + 1, right - 1);
}
결론
당신의 코 틀린의 이 호출로 방법은 작은 재귀 깊이가 Intrinsics.checkParameterIsNotNull(s, "s")
그보다 무거운 따라서 모든 단계에서와 자바 대응. 이 자동 생성 방법을 원하지 않으면 여기에 응답 된대로 컴파일하는 동안 null 검사를 비활성화 할 수 있습니다
그러나 어떤 이점 tailrec
이 재귀 호출을 반복 호출로 변환 하는지 이해 하므로 해당 기능을 사용해야합니다.
tailrec
하거나 재귀를 피하는 것입니다. 사용 가능한 스택 크기는 실행, JVM 및 설정 사이, 방법 및 해당 매개 변수에 따라 다릅니다. 그러나 순수한 호기심을 요구한다면 (완벽히 좋은 이유입니다!) 확실하지 않습니다. 아마도 바이트 코드를 봐야 할 것입니다.