Доступ к элементам кортежа

Да, несмотря на все плюсы модели памяти Rust, все же приходится признать – это для очень упорных программистов. В крайнем случае у меня создалось именно такое ощущение в процессе выяснения в “рассылке” как же мне написать функции доступа к элементам кортежа. В сам язык встроена следующая возможность:

fn foo() -> (uint, uint) { (1, 2) }
...
let (l, r) = foo();
io::println(fmt!("Left value = %u, write value = %u", l, r));

В то же время, мне хотелось получить доступ к элементу кортежа без дополнительных “приседаний”, где-то так:

let pair = foo();
io::println(fmt!("Left value = %u, write value = %u",
    pair._1(), pair._2()));


Идея как это реализовать пришла в голову довольно быстро:

pub trait TupleVal<T> {
    fn _1() -> T;
    fn _2() -> T;
}

impl <T>(T, T): TupleVal<T> {
    fn _1() -> T {
        let (a, _) = self;
        a
    }
    fn _2() -> T {
        let (_, b) = self;
        b
    }
}

Что само собой не скомпилировалось, так как компилятор отказался возвращать ссылку на элемент кортежа без указания времени жизни самого кортежа. Тоесть, компилятору необходимо “сказать” о том, что возвращаемый элемент кортежа будет жить не больше чем сам кортеж, что можно сделать так:

trait TupleVal<T> {
    fn _1(&self) -> &self/T;
    fn _2(&self) -> &self/T;
}
impl <T>(T, T): TupleVal<T> {
    fn _1(&self) -> &self/T {
        match *self { (ref a, _) => a }  // Первый способ получить значения кортежа
    }
    pure fn _2(&self) -> &self/T {
        let &(_, ref b) = self;   // Второй способ получить значения кортежа
        b
    }
}

Во втором случае используется ключевое слово self, обозначающее время жизни текущего объекта. Таким образом, запись &self/T для возвращаемого объекта означает: указатель с таким же временем жизни как и текущий объект. Это как раз то, что мне и хотелось получить изначально.
Следующим не очевидным для меня моментом было использование ключевого слова ref. Без него компилятор считает что необходимо создать копию объектов на стеке, а мне это, во-первых, совершенно не нужно, во-вторых, стековый объект не будет соответствовать задекларированному возвращаемому значению функции.
Да, вариант 2 не будет работать как минимум до Rust 0.7.

2 Comments Доступ к элементам кортежа

Leave a Reply