log
,还有不少选择:env_logger
,tracing
,slog
,simplelog
等等,最佳实践是什么?log
和 tracing
,后者功能更强大因为它支持结构化日志记录,但前者更普遍。还有另一个结构化日志接口 slog,比 tracing
更古老但用的较少。每个日志接口都有自己生态系统,可以根据自己的需要选择。如果在写一个库,log
是个不错的选择,因为所有的日志记录接口都与它兼容。但如果你确实需要结构化日志记录,则可以改用 tracing
,这取决于你的需求,比如你是需要写到文件还是只是终端。tracing
的接口:tracing_log - Rust,有多个同时操作交错日志消息时特别方便,可以按某些属性对它们进行分组并单独查看它们。(来自 class_two_perversion)logging
和 JS 的 Winston
。(来自 RapBeautician)tokio::spawn
生成新任务来下载 PDB,并修复了编译器报的错误,它可以正常工作了。Rust 编译器输出一个二进制文件,它可以在任何地方运行,没有运行时依赖。requests
,只要 import requests
就可以使用了。Rust 的 reqwest
也是如此,只要输入 cargo add reqwest
就可以在代码中使用它。requests
是程序的依赖,用户需要后去后才能使用。此外,由于弱类型和错误处理能力(与 Rust 比),Python 变得更加劣势。这一点上,我可以使用 Rust 比使用 Python 更快地编写原型工具,并且我可以自信地知道我的工具比等效的 Python 更易于维护且寿命更长。但是,对于短期工具,Python 可能仍然更好,因为它不需要启动项目即可在 VSCode 中获得智能感知支持。 Rust 的 cargo-script 接近将 Rust 推入脚本语言的领域,但不幸的是,我还没有在 VSCode 中找到与之集成的插件。TaggedCell
和 Tag
类型实现,为了安全操作,TaggedCell
的每个实例都必须是唯一的。然后必须通过 TaggedCell::init ()
初始化 TaggedCell
,它使用用户提供的函数或闭包初始化底层数据,然后返回一个特殊的零大小的 Init<Tag>
用于访问 Cell 的数据。为了确保每个单元格使用唯一的标签类型,tagged_cell!
提供宏。该宏根据变量的名称创建一个新的标记类型,并将其应用到声明中。use tagged_cell::tagged_cell;
tagged_cell!{
static BAR: TaggedCell<Vec<usize>, _> = TaggedCell::new();
}
let tag = BAR.init(|| vec![0, 10, 20]);
let vec = BAR.get(tag);
assert_eq!(vec[2], 20);
TaggedCell::init
才会初始化 Cell 的数据。所有未来的 TaggedCell::init
调用都将返回一个新标签。未确定哪个线程将初始化 Cell 的数据。use std::thread;
use tagged_cell::tagged_cell;
tagged_cell!{
static TABLE: TaggedCell<Vec<usize>, _> = TaggedCell::new();
}
thread::spawn(move || {
let tag = TABLE.init(|| vec![0, 10, 20]);
let table = TABLE.get(tag);
assert_eq!(table[2], 20);
});
thread::spawn(move || {
let tag = TABLE.init(|| vec![0, 10, 20]);
let table = TABLE.get(tag);
assert_eq!(table[1], 10);
});
use ukanren::*;
fn appendo(first: Value, second: Value, out: Value) -> BoxedGoal<impl Iterator<Item = State>> {
eq(&first, &())
.and(eq(&second, &out))
.or(fresh(move |a: Value, d: Value, res: Value| {
eq(&(a.clone(), d.clone()), &first)
.and(eq(&(a.clone(), res.clone()), &out))
.and(appendo(d.clone(), second.clone(), res))
}))
.boxed()
}
let goal = fresh(|x, y| appendo(x, y, [1, 2, 3, 4, 5].to_value()));
assert_eq!(
goal.run(2).collect::<Vec<_>>(),
vec![
state![(), [1, 2, 3, 4, 5]],
state![[1], [2, 3, 4, 5]],
state![[1, 2], [3, 4, 5]],
state![[1, 2, 3], [4, 5]],
state![[1, 2, 3, 4], [5]],
state![[1, 2, 3, 4, 5], ()],
],
);
2*4*6*8*11*14*17*2
正好有 18 个字符。当处理 50 万个字符时会比较省事。$ ./rust-counter-strings 50
# 2*4*6*8*11*14*17*20*23*26*29*32*35*38*41*44*47*50*
From 日报小组 长琴