Kotlin: `tailrec` в методе экземпляра против функции расширения - PullRequest
1 голос
/ 27 апреля 2020

В приведенном ниже коде я вижу предупреждение no tail calls found, но та же функция, если она написана как функция расширения, не имеет этого предупреждения. Теперь я запутался, является ли моя IDE неправильной, или мой метод Extension на самом деле не является хвост-рекурсивным или есть разница между тем, как компилятор работает с методами Instance по сравнению с функциями Extension. enter image description here

1 Ответ

2 голосов
/ 27 апреля 2020

Как и второе предупреждение

Рекурсивный вызов не является хвостовым вызовом

указывает, что этот вызов является рекурсивным, но не является хвостовым вызовом.

Это потому, что функция вызывается с другим экземпляром в качестве своей цели (next, а не this), поэтому tailrec на самом деле не имеет эффекта в этом случае. Если вы замените цель на this, компилятор прекратит выдавать любые предупреждения.

Я предполагаю, что функция расширения компилируется без каких-либо предупреждений, потому что они скомпилированы как функции stati c (то есть не экземпляра), где цель - просто другой параметр, означающий, что преобразованный код выглядит (примерно) как

@Nullable
public static final SLLNode2 getNodeForValue2(@NotNull SLLNode2 $this$getNodeForValue2, int valToFind) {
    Intrinsics.checkParameterIsNotNull($this$getNodeForValue2, "$this$getNodeForValue2");
    if ($this$getNodeForValue2.getValue() == valToFind) {
        return $this$getNodeForValue2;
    } else {
        SLLNode2 var10000 = $this$getNodeForValue2.getNext();
        return var10000 != null ? getNodeForValue2(var10000, valToFind) : null;
    }
}

, который довольно ясно содержит рекурсивный вызов хвоста.


Однако я не убедитесь, что это различие является преднамеренным, поскольку способ компиляции функций расширения должен быть деталью реализации, а пример функции экземпляра должен (?) быть эквивалентно оптимизируемым.


Редактировать: это кажется, это на самом деле ошибка .

...