LINUX.ORG.RU

Изучая Rust...

 , ,


1

4

Здравствуйте. Пытаюсь реализовать список на Rust. Вот что у меня получилось:

use std::fmt;

struct Node {
    value: i32,
    link: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Node {
        Node { value: value, link: None, }
    }

    fn append(&mut self, value: i32) {
        match self.link {
            Some(ref mut node) => node.append(value),
            None => self.link = Some(Box::new(Node::new(value))),
        }
    }

    fn length(&self) -> i32 {
        match self.link {
            Some(ref node) => node.length() + 1,
            None => 1,
        }
    }

    fn insert_after(&mut self, value: i32, after: i32) -> bool {
        if self.value == after {
            self.link = Some(Box::new(Node { value: value, link: self.link.take() }));
            true
        }
        else {
            match self.link {
                Some(ref mut node) => node.insert_after(value, after),
                None => false,
            }
        }
    }
}

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.value)
        while
    }
}

fn main() {
    let mut stack = Node::new(1024);

     stack.append(67);

     println!("{}", stack);
}

Подскажите, как можно напечатать все элементы списка? В текущей реализации выводится только первый элемент.


Например

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut node = self;
        
        loop {
          try!(write!(f, "{} ", node.value));
          
          if let Some(ref link) = node.link {
            node = link;
          } else {
            break;
          }
        }
        
        Ok(())
    }
}
theNamelessOne ★★★★★
()
Ответ на: комментарий от anonymous

Чем грузины. Ну а вообще проходи мимо.

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

Что тебе не нравится, я не понял. Я недавно зарегался. Не знаю что вы там придумали. Меня ничего кроме Rust не интересует и я не отписывался нигде, помимо заданных мною вопросов.

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

Ты хочешь сказать я похож на 14-летнего ребенка?

Вообще-то это было про romeo250501, но если тебя это так задевает, — да.

anonymous
()
Ответ на: комментарий от Ivana

одни растаманы

не углядет растаманов. сплошь хипсторы

anonymous
()
Ответ на: комментарий от paret

Collection - это трейт или тип?

Может я что то не так понял, но в чем проблема то?

struct MyVec<T>{
    inner: Vec<T>
}

use std::fmt;

impl<T> fmt::Debug for MyVec<T> where T: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (&self.inner as &fmt::Debug).fmt(f)
    }
}

fn main() {
    let vec = MyVec{inner: vec![1u32, 2, 3]};
    println!("{:?}", vec);
}
[/rust]

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

Может я что то не так понял, но в чем проблема то?

Проблема в том, что ты реализуешь трейт для конкретного MyVec<T>, а он хочет чтобы сам MyVec - был дженерик-типом.

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

Металлисты и прочие анонимусы там есть

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

Не смотри и все будет норм. Тебя кто-то заставляет использовать его или учить?

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

Больной, примите дозу живительного С++ и всё пройдёт.

  std::cout << "ptr = 0x" << std::hex << std::uppercase << std::fill('0') << std::setw(8) << static_cast<uintptr_t>(ptr) << std::nouppercase << std::dec << std::endl;
red75prim ★★★
()
Ответ на: комментарий от red75prim

Больные сравнивают теплое с мягким. Если уж приводить аналог на С++ то того, что у ТС + то, что ему посоветовали:

#include <iostream>
#include <memory>
using namespace std;

struct Node {
    int value;
    unique_ptr<Node> link;
    
    void append(int n) {
        link ? 
            link->append(n) : 
            link.reset(new Node {n});
    }
    
    int length() const {
        return link ? link->length() + 1 : 1;
    }
    
    bool insert_after(int n, int after) {
        return value == n ?
            link.reset(new Node {n, move(link)}), true :
            link && link->insert_after(n, after);
    }
};

ostream& operator<<(ostream& os, const Node& n) {
    os << n.value << ' ';
    return n.link ? os << *n.link : os;
}

int main() {
    Node stack {1024};
    stack.append(67);

    cout << stack;
}

Против:

use std::fmt;

struct Node {
    value: i32,
    link: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Node {
        Node { value: value, link: None, }
    }

    fn append(&mut self, value: i32) {
        match self.link {
            Some(ref mut node) => node.append(value),
            None => self.link = Some(Box::new(Node::new(value))),
        }
    }

    fn length(&self) -> i32 {
        match self.link {
            Some(ref node) => node.length() + 1,
            None => 1,
        }
    }

    fn insert_after(&mut self, value: i32, after: i32) -> bool {
        if self.value == after {
            self.link = Some(Box::new(Node { value: value, link: self.link.take() }));
            true
        }
        else {
            match self.link {
                Some(ref mut node) => node.insert_after(value, after),
                None => false,
            }
        }
    }
}

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut node = self;
        
        loop {
          try!(write!(f, "{} ", node.value));
          
          if let Some(ref link) = node.link {
            node = link;
          } else {
            break;
          }
        }
        
        Ok(())
    }
}

fn main() {
    let mut stack = Node::new(1024);

     stack.append(67);

     println!("{}", stack);
}
anonymous
()
Ответ на: комментарий от anonymous

link.reset(new Node {n, move(link)})

Тут, конечно, не хватает метода emplace, было бы так:

link.emplace(n, move(link));

В optional из невышедшего еще С++17 он есть, а в unique_ptr к сожалению нет. Впрочем и так выглядит всяко лучше чем:

self.link = Some(Box::new(Node { value: value, link: self.link.take() }));
anonymous
()
Ответ на: комментарий от anonymous

Красиво. А потом используем этот список из нескольких потоков и оказывается, что это не совсем аналог. Опять же есть std::collections::LinkedList , но по соображениям производительности обычно лучше использовать Vec.

Насчет реализации списков на Rust можно посмотреть http://cglab.ca/~abeinges/blah/too-many-lists/book/

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

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

Зачем?

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

Можно подробней - почему не аналог?

Тем более каким образом прибитое левое, изначально не поставленное условие каким-то образом делает не аналог из того, что есть полный аналог? Такой методой можно оправдать всё что угодно. Захреначивает куллязык и добавляем туда всё подряд, а когда(всегда) он будет сливать - будем говорить, что не аналог. Хотя прости, да, я описал раст.

Опять же есть std::collections::LinkedList , но по соображениям производительности обычно лучше использовать Vec.

Он же не аналог. Получается vec юзать нельзя и сравнивать с листом, ибо неаналог. Как быть - как дальше жить? Взаимоисключающие параграфы они такие.

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

static_cast, потому что ptr может быть char*, который совсем не ptr, а вроде бы как строка. А остальное, чтобы изобразить printf(«ptr = 0x%8X», ptr)

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

А остальное, чтобы изобразить printf(«ptr = 0x%8X», ptr)

А зачем его изображать в С++? Потоки это альтернативный, а не единственный путь, там есть тот же printf в <cstdio>.

anonymous
()
Ответ на: комментарий от red75prim

А потом используем этот список из нескольких потоков и оказывается, что это не совсем аналог

Напиши код на Rust, который будет дергать список ТС из нескольких потоков. Тогда и можно будет говорить про аналог.

anonymous
()
Ответ на: комментарий от registrant27492

Зачем? Можно подробней - почему не аналог?

Потому что забыли посмотреть в документацию, где может быть написано (если не забыли), что этот список потоконебезопасен. А в Rust это просто не скомпилируется. Так что добавьте к примеру документацию и code-reviewer'ов.

Тем более каким образом прибитое левое, изначально не поставленное условие каким-то образом делает не аналог из того, что есть полный аналог?

В коде на С++ потоконебезопасность никак не отражена. В коде на Rust отражена. Так что полным аналогом это быть не может.

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

А зачем его изображать в С++? Потоки это альтернативный, а не единственный путь, там есть тот же printf в <cstdio>.

Угу. Для этого cout и cin синхронизируются с stdin и stdout по умолчанию, из-за чего начинают сильно тормозить. Для максимальной производительности нужно отключать синхронизацию, но тогда смешивать printf и cout очень не рекомендуется. Так что либо тормоза, либо то что я написал, либо только printf, включая и библиотеки.

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

Так что полным аналогом это быть не может.

Окей, мне понадобилось в С++ добавить работу с тредами - я могу быстро ее реализовать c помощью блокировок (да-да, не всегда самый лучший путь):

#include <future>
#include <iostream>
#include <memory>
using namespace std;

struct Node {
    int value;
    unique_ptr<Node> link;
    mutable mutex lock;
    
    void append(int n) {
        lock_guard<mutex> _ { lock };
        
        link ? 
            link->append(n) : 
            link.reset(new Node{n});
    }
    
    int length() const {
        lock_guard<mutex> _ { lock };
        
        return link ? link->length() + 1 : 1;
    }
    
    bool insert_after(int n, int after) {
        lock_guard<mutex> _ { lock };
        
        return value == after ?
            link.reset(new Node{n, move(link)}), true :
            link && link->insert_after(n, after);
    }
};

ostream& operator<<(ostream& os, const Node& n) {
    lock_guard<mutex> _ { n.lock };
    
    os << n.value << ' ';
    return n.link ? os << *n.link : os;
}

int main() {
    Node stack{1024};
    
    async( launch::async, [&]{ stack.insert_after( 1025, 1024 ); } ),
    async( launch::async, [&]{ stack.append( 1026 ); } );

    cout << stack << '\n';
}

Итого +5 строк кода для данного примера. Сколько нужно написать на Rust?

anonymous
()
Ответ на: комментарий от red75prim

Угу. Для этого cout и cin синхронизируются с stdin и stdout по умолчанию, из-за чего начинают сильно тормозить.

http://stackoverflow.com/a/896665/3792661. Если писать '\n' вместо endl, то разницы нет.

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

Сколько нужно написать на Rust?

Много. Но, по крайней мере, race-condition не будет. У вас mutex на каждой ноде, race-condition при вызове append на двух разных нодах принадлежащих к одному списку.

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

static_cast, потому что ptr может быть char*, который совсем не ptr, а вроде бы как строка.

Я помню как я тебе жопу рвал пытаясь вывести чар не как символ. Но это не проблема С++, вернее это общая проблема - она будет везде.

Хотя этого можно было бы избежать, если бы кресты осилили бы обёртки над равмемом.

А остальное, чтобы изобразить printf(«ptr = 0x%8X», ptr)

Зачем? В чём проблема с %p?

registrant27492
()
Ответ на: комментарий от red75prim

Но, по крайней мере, race-condition не будет. У вас mutex на каждой ноде, race-condition при вызове append на двух разных нодах принадлежащих к одному списку.

Все будет как надо, как только append одной из нод дойдет до второй - он будет ждать окончания вставки и только тогда пойдет дальше. Единственно, что нет гарантии, что «твой» append вставит элемент раньше append из параллельного треда. Но этой гарантии вообще не может быть, только если самостоятельно синхронизировать треды.

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