检测新的struct初始化

时间:2016-05-02 23:32:46

标签: struct rust rust-cargo

我来自大多数OOP语言,所以让这个概念在Rust有点工作似乎很难。我想实现一个基本的计数器,它可以计算我为这种类型制作了多少“实例”,并将它们保存在一个向量中供以后使用。

我尝试了很多不同的东西,首先是制作一个静态向量变量,但由于它不允许具有析构函数的静态东西,因此无法完成。

这是我的第一次尝试:

struct Entity {
    name: String,
}

struct EntityCounter {
    count: i64,
}

impl Entity {
    pub fn init() {
        let counter = EntityCounter { count: 0 };
    }

    pub fn new(name: String) {
        println!("Entity named {} was made.", name);
        counter += 1; // counter variable unaccessable (is there a way to make it global to the struct (?..idek))
    }
}

fn main() {
    Entity::init();
    Entity::new("Hello".to_string());
}

第二

struct Entity {
    name: String,
    counter: i32,
}

impl Entity {
    pub fn new(self) {
        println!("Entity named {} was made.", self.name);
        self.counter = self.counter + 1;
    }
}

fn main() {
    Entity::new(Entity { name: "Test".to_string() });
}

这些都不起作用,我只是尝试了一些关于如何实现这样一个功能的概念。

1 个答案:

答案 0 :(得分:4)

您的问题似乎比您描述的更为根本。你有点在墙上扔代码看看有什么东西,这根本就不会让你到任何地方。我建议在继续之前完全阅读the Rust Book。如果你不理解其中的某些内容,请询问它。就目前而言,您将证明您不了解变量范围,返回类型,实例构造的工作原理,静态工作方式以及参数的传递方式。这是一个真正摇摇欲坠的基础,试图建立任何理解。

在这种特殊情况下,你要求某些故意不直接。你说你想要一个计数器一个实例向量。计数器很简单,但实例的向量? Rust不允许像其他语言一样轻松共享,所以你如何做到这一点取决于严重实际打算使用它。

以下是非常粗略猜测某些可能与您想要的模糊相似的东西。

/*!
Because we need the `lazy_static` crate, you need to add the following to your
`Cargo.toml` file:

```cargo
[dependencies]
lazy_static = "0.2.1"
```
*/

#[macro_use] extern crate lazy_static;

mod entity {
    use std::sync::{Arc, Weak, Mutex};
    use std::sync::atomic;

    pub struct Entity {
        pub name: String,
    }

    impl Entity {
        pub fn new(name: String) -> Arc<Self> {
            println!("Entity named {} was made.", name);
            let ent = Arc::new(Entity {
                name: name,
            });
            bump_counter();
            remember_instance(ent.clone());
            ent
        }
    }

    /*
    The counter is simple enough, though I'm not clear on *why* you even want
    it in the first place.  You don't appear to be using it for anything...
    */
    static COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

    fn bump_counter() {
        // Add one using the most conservative ordering.
        COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
    }

    pub fn get_counter() -> usize {
        COUNTER.load(atomic::Ordering::SeqCst)
    }

    /*
    There are *multiple* ways of doing this part, and you simply haven't given
    enough information on what it is you're trying to do.  This is, at best,
    a *very* rough guess.

    `Mutex` lets us safely mutate the vector from any thread, and `Weak`
    prevents `INSTANCES` from keeping every instance alive *forever*.  I mean,
    maybe you *want* that, but you didn't specify.

    Note that I haven't written a "cleanup" function here to remove dead weak
    references.
    */
    lazy_static! {
        static ref INSTANCES: Mutex<Vec<Weak<Entity>>> = Mutex::new(vec![]);
    }

    fn remember_instance(entity: Arc<Entity>) {
        // Downgrade to a weak reference.  Type constraint is just for clarity.
        let entity: Weak<Entity> = Arc::downgrade(&entity);
        INSTANCES
            // Lock mutex
            .lock().expect("INSTANCES mutex was poisoned")
            // Push entity
            .push(entity);
    }

    pub fn get_instances() -> Vec<Arc<Entity>> {
        /*
        This is about as inefficient as I could write this, but again, without
        knowing your access patterns, I can't really do any better.
        */
        INSTANCES
            // Lock mutex
            .lock().expect("INSTANCES mutex was poisoned")
            // Get a borrowing iterator from the Vec.
            .iter()
            /*
            Convert each `&Weak<Entity>` into a fresh `Arc<Entity>`.  If we
            couldn't (because the weak ref is dead), just drop that element.
            */
            .filter_map(|weak_entity| weak_entity.upgrade())
            // Collect into a new `Vec`.
            .collect()
    }
}

fn main() {
    use entity::Entity;

    let e0 = Entity::new("Entity 0".to_string());
    println!("e0: {}", e0.name);
    {
        let e1 = Entity::new("Entity 1".to_string());
        println!("e1: {}", e1.name);

        /*
        `e1` is dropped here, which should cause the underlying `Entity` to
        stop existing, since there are no other "strong" references to it.
        */
    }
    let e2 = Entity::new("Entity 2".to_string());
    println!("e2: {}", e2.name);

    println!("Counter: {}", entity::get_counter());

    println!("Instances:");
    for ent in entity::get_instances() {
        println!("- {}", ent.name);
    }
}