Ни один из них не является хвостовой рекурсией.Это происходит только тогда, когда рекурсивные вызовы происходят только как самый последний элемент вдоль некоторого пути выполнения.Если вы могли бы заменить вызов переходом к началу кода, не сохраняя состояния, а переименовывая входные переменные, то это хвостовая рекурсия.(Внутренне это именно то, что делает компилятор.)
Чтобы преобразовать обычную рекурсивную функцию в хвостовую рекурсивную функцию, когда это возможно, вам необходимо передать любые сохраненные данные, например, так:
private def getAddresses(
data: List[Int], count: Int, len: Int, // You had this already
addresses: List[Address] = Nil, // Build this as we go, starting with nothing
positions: List[Int] = Nil // Same here
): (List[Address], List[Int]) {
if (count==len) {
(addresses.reverse, positions.reverse) // Return what we've built, reverse to fix order
}
else {
val (addr,rest) = data.span(_ != 0)
val newdata = rest.tail
val position = addr.length + 1
val flag = addr.head
val address = (
if (flag) SMEAddress().fromBytes(addr)
else DistributionList().fromBytes(addr)
)
getAddresses(newdata, count+1, len, address :: addresses, position :: positions)
}
}
Хвосто-рекурсивные версии более эффективны, чем нехвосто-рекурсивные версии, если все остальное равно.(В этом случае это может быть не так, поскольку список должен быть полностью изменен в конце, но у него есть огромное преимущество: он не переполняет стек, если вы используете большой len
.)
Вызов метода дважды всегда запускает его дважды.Автоматическое запоминание результатов вызовов методов отсутствует - это будет чрезвычайно сложно сделать автоматически.