在Rust中的静态结构体

4
我正在使用Nickel.rs构建一个待办事项列表示例。由于目前不支持闭包,我正在尝试找到另一种处理所实现的简单结构的方法。
以下是我的代码:
extern crate nickel;

use std::io::net::ip::Ipv4Addr;
use nickel::{Nickel, Request, Response};

struct TaskList {
    list: Vec<String>
}

impl TaskList {
    fn new() -> TaskList {
        TaskList { list: Vec::new() }
    }

    fn add_task (&mut self, task: &str) {
        &self.list.push(task.to_string());
    }

    fn get_tasks (&self) -> Vec<String> {
        self.list.to_vec()
    }
}

fn main() {
    let mut server = Nickel::new();

    static mut sample : TaskList = TaskList { list: Vec::new() };

    sample.add_task("First");
    sample.add_task("Second");

    fn fetch_tasks (_request: &Request, response: &mut Response) {
        response.send(sample.get_tasks().to_string())
    }

    server.utilize(Nickel::static_files("./public"));

    server.get("/task", fetch_tasks);
    server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
}

但编译器给我写了这个错误信息:"可变静态项不允许有析构函数"。
您有什么建议可以解决这个问题吗?
1个回答

0

我不太确定你想要实现什么。

如果你想让TaskList存在于堆上,可以使用Box。然而,栈作用域应该在server.listen()内部有效,所以我不明白为什么你需要将TaskList设置为static mut?

如果你想要玩弄静态变量,你必须以不安全的方式进行操作,就像这样:

use std::mem::transmute;
use std::ptr;

struct Static {
  v: int
}

impl Static {
  fn whatever(&mut self) {
    println!("Write to static");
    self.v += 1;
  }
}

static mut _data:*const Static = 0 as *const Static;

unsafe fn get<'a>() -> &'a mut Static {
  if _data == ptr::null::<Static>() {

    // Notice this is a Box<Static>, which is a *Static allocated on the heap
    // transmute(Static { v: 0 }) wouldn't work because once the stack scope ends
    // the instance would no longer be valid; Box<T> lasts beyond the call to get()
    _data = transmute(box Static { v: 0 });
  }
  return transmute(_data);
}

unsafe fn release() {
  ptr::read::<Static>(_data);
}

impl Drop for Static {
  fn drop(&mut self) {
    println!("Dropped static");
  }
}

fn main() {
  unsafe {
    let foo = get();
    foo.whatever();
  }
  unsafe {
    let foo = get();
    foo.whatever();
  }
  unsafe {
    release();
  }
  println!("Done");
}

我非常强烈不建议这样做,除非有非常好的理由。

大多数情况下,您可以假设在一个作用域中创建的变量:

{
   let foo = Bar; 
   ...
} <-- End

在该作用域结束之前将继续有效。

类似于 server.get 的子调用仍然在定义 sample 的 main() { } 作用域内。

它仍然是有效的。


我最初认为,如果不将“sample”变量设为静态变量,它将可以在函数“fetch_tasks”中访问(因为它是在main(){}中定义的)。但编译器告诉我不能在“fetch_task”中捕获动态环境,所以我必须使用闭包。但是router.get()需要一个函数作为其第二个参数。 - ThomasC__
@ThomasC__ 你可能需要使用“中间件”,以便在给定“请求”上下文的情况下访问到你的TaskList句柄。也许可以查看一些中间件的示例。 - BurntSushi5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接