检测新的结构初始化

Detecting new struct initialization

我主要来自 OOP 语言,所以让这个概念在 Rust 中工作似乎有点困难。我想实现一个基本计数器,用于计算我用这种类型制作了多少 "instances",并将它们保存在一个向量中供以后使用。

我尝试过很多不同的东西,首先是创建一个静态向量变量,但由于它不允许具有析构函数的静态变量,所以无法完成。

这是我的第一次尝试:

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() });
}

None 这些工作中,我只是在尝试一些关于如何实现这样的功能的概念。

您的问题似乎比您描述的更为根本。你有点像把代码扔到墙上看看有什么粘住,而这根本不会让你到任何地方。我建议在继续之前完整阅读 the Rust Book。如果您不明白其中的某些内容,请询问。就目前而言,您表明您不了解变量作用域、return 类型、实例构造如何工作、静态如何工作以及参数如何传递。这是一个 确实 不稳定的基础,可以尝试建立任何理解。

在这种特殊情况下,您要求的东西故意不直截了当。你说你想要一个计数器 一个实例向量。计数器很简单,但是一个实例向量? 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);
    }
}