Реализация интерфейса для &str

44 views
Skip to first unread message

Mike Potanin

unread,
Sep 25, 2014, 5:29:49 AM9/25/14
to rust-r...@googlegroups.com

Добрый день!
Пытаюсь сделать простенький (пока нет ассоциированных типов) интерфейс для иммутабельных последовательностей и реализовать его для строк:

pub trait Seq<T> {
    fn pop(self) -> Option<(T, Self)>;
}

impl Seq<char> for &str {
    fn pop(self : &str) -> Option<(char, &str)> { Some((self.char_at(0), self.slice_from(1) )) }
}

Но компилятор на все попытки невнятно ругается.
Можно ли это победить?

Владимир Матвеев

unread,
Sep 25, 2014, 5:42:23 AM9/25/14
to rust-r...@googlegroups.com
Привет!

Здесь есть несколько проблем. Во-первых, у self не нужно указывать тип. Во-вторых, lifetime elision в данном случае не сработает правильно, и все аннотации нужно писать явно. В-третьих, интерфейс не совсем корректный - если в коллекции ничего нет, то pop() вернёт None, но исходная коллекция будет недоступна, потому что метод принимает self по значению. Для &str это не страшно, потому что он Copy, но для других коллекций вроде Vec уже будут проблемы. Поэтому пустую коллекцию нужно возвращать обратно - если она не понадобится, то значение можно будет просто проигнорировать.

Вот рабочий вариант:

pub trait Seq<T> {
    fn pop
(self) -> Result<(T, Self), Self>;
}

impl
<'a> Seq<char> for &'a str {
    fn pop
(self) -> Result<(char, &'a str), &'a str> {
       
if self.is_empty() {
           
Err(self)
       
} else {
           
Ok((self.char_at(0), self.slice_from(1)))
       
}
   
}
}

fn process
(s: &str) {
    match s
.pop() {
       
Ok((c, rest)) => {
            println
!("{}<{}>", c, rest);
            process
(rest);
       
}
       
Err(s) => println!("<{}> is empty", s)
   
}
}

fn main
() {
    let s
= "abcdefg";
    process
(s);
}

play
Reply all
Reply to author
Forward
0 new messages