LINUX.ORG.RU

раскрытие рекурсии в расте(lifetime)

 


1

5

Дорогие растовчане. У меня есть к вам вопрос. Я неоднократно сталкивался с проблемой замены рекурсии на цикл в расте. Например вот такая абстрактная ситуация:

struct Lazy<T> {...}

impl<T> Lazy<T> {
	fn force(&mut self) -> &mut T {...}
}

struct InfLazyList<T> {
	head : T,
	tail : Lazy<InfLazyList<T>>
}

impl<T> InfLazyList<T> {
	fn index(&mut self, i : usize) -> &T {
		if i == 0 {
			&self.head
		} else {
			self.tail.force().index(i - 1)
		}
	}
}
Как бе все норм. Но хочу следать индексирование итеративным.
	fn index(&mut self, i : usize) -> &T {
		let mut top : &mut InfLazyList<T> = &mut self;
		while i > 0 {
			top = top.tail.force();
		}
		&top.head
	}
Ну и сразу «cannot assign to `top` because it is borrowed». Есть какой-то способ сделать это не прибегая к unsafe?

★★★★★

Последнее исправление: Aswed (всего исправлений: 1)

Можно полный пример?

Но хочу следать индексирование итеративным.

Зачем?

let mut top : &mut InfLazyList<T> = &mut self;

Не многовато ли? Разве let top = &mut self не достаточно?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

top меняется в цикле. Без mut не будет меняться.

Aswed ★★★★★
() автор топика
Последнее исправление: Aswed (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Можно полный пример?

Сейчас это скорее абстрактная ситуация. Ранее я сталкивался с этим когда писал транслятор и там была рекурсивная проверка типов.

Зачем?

Ну епт! Потому что циклы более производительные чем рекурсия. Раст вроде как подается как высокопроизводительный. А автоматической развертки хвостовой рекурсии в циклы компилятор не умеет. Об этом как-то писали создатели, что там неопределенная ситуация с временем жизни может случиться.

Aswed ★★★★★
() автор топика
Последнее исправление: Aswed (всего исправлений: 1)
Ответ на: комментарий от anonymous

«Если у тебя в из инструметов только молоток, все выглядит как гвоздь»(с)

Aswed ★★★★★
() автор топика
Ответ на: комментарий от Aswed

Твой пример очень похож на «Problem case #4: mutating &mut references» из Nonlexical Lifetimes RFC. Попробуй workaround оттуда.

https://github.com/nikomatsakis/nll-rfc/blob/master/0000-nonlexical-lifetimes...

pftBest ★★★★
()
Последнее исправление: pftBest (всего исправлений: 1)
Ответ на: комментарий от pftBest

Спасибо за ссылку. Интересный гайд по lifetime. Вечером посмотрю.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от Aswed

Потому что циклы более производительные чем рекурсия.

Доу, я не так понял. Я подумал, что вы хотите использовать c-style циклы, а не итераторы.

RazrFalcon ★★★★★
()
Ответ на: комментарий от Virtuos86

Например так

fn gen_fibs() -> USeq {
	fn rec(a : usize, b : usize) -> USeq {
		InfLazyList{head : a, tail : lazy!(rec(b, a+b))}
	}
	rec(1, 1)
}
Как я уже сказал, это абстрактный пример.
Ну и lazy собсна в довесок

struct Lazy<T> {
	val : LazyVal<T>
}

enum LazyVal<T> {
	Forced(Box<T>),
	NotForced(Box<Fn()->T>),
	Nil
}

macro_rules! lazy {
	($expr:expr) => {
		Lazy {
			val : LazyVal::NotForced(Box::new(move||$expr)),
		}
	}
}

impl<T> Lazy<T> {
	fn force(&mut self) -> &mut T {
		match self.val {
			LazyVal::Forced(ref mut val) => return val,
			_ => ()
		}
		match mem::replace(&mut self.val, LazyVal::Nil) {
			LazyVal::NotForced(fnc) => {
				self.val = LazyVal::Forced(Box::new(fnc()));
				match self.val {
					LazyVal::Forced(ref mut val) => return val,
					_ => panic!()
				}
			},
			_ => panic!()
		}
	}
}

Aswed ★★★★★
() автор топика
Последнее исправление: Aswed (всего исправлений: 1)
Ответ на: комментарий от pftBest

offtop

А вы случайно не знаете, что там комитет думает про box синтакс? Его стабилизировтаь собираются? Это который «box foo()» вместо «Box::new(foo())»

Aswed ★★★★★
() автор топика
Ответ на: offtop от Aswed

нет, про box я давно не слышал.

pftBest ★★★★
()
Ответ на: offtop от Aswed

я думаю его не будут трогать пока не решат все проблемы с кастомными алокаторами и placement new.

pftBest ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.