在vec!宏实现中有这样的规则:
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
);
Run Code Online (Sandbox Code Playgroud)
<[_]>里面到底是什么?
我正在使用Anyhow并有一个返回的函数anyhow::Result。在该函数中,我想“解开”一个选项,以便如果选项值为None,则返回带有特定错误消息的错误。这就是我所做的:
let o: Option<i32> = ...;
let v: i32 = o.ok_or_else(|| anyhow!("Oh, boy!"))?;
// here I need v only
Run Code Online (Sandbox Code Playgroud)
ok_or_else()出于ok_or()性能原因,我使用了 not 。
我通常对此表示同意,但想知道这是否是做我想做的事情的最简单(最简洁)的方法(不牺牲性能)?
我在 Rust 代码中经常看到这种情况。以下是标准库中的一些示例:
impl<T> const Default for Option<T> {...}
impl const From<char> for u64 {...}
Run Code Online (Sandbox Code Playgroud)
什么是impl const?
最初,我非常惊讶地发现HashMap,即使使用FNV哈希器,Rust 的速度也比 Java、.NET、PHP 中的等效项慢得多。我说的是优化的Release模式,而不是Debug模式。我做了一些计算,发现 Java/.NET/PHP 中的计时值低得令人怀疑。然后它击中了我 - 尽管我正在使用一个大哈希表(数百万个条目)进行测试,但我读取的主要是顺序键值(如14, 15, 16, ...),这显然导致了大量CPU 缓存命中,这是由于标准哈希表的方式(以及整数和短字符串的哈希码函数)在这些语言中被实现,因此具有附近键的条目通常位于附近的内存位置。
HashMap另一方面,Rust使用所谓的SwissTable实现,它显然以不同的方式分配值。当我测试随机键的阅读时,一切都井然有序——“竞争对手”的得分落后于 Rust。
因此,如果我们处于需要按顺序执行大量获取的情况,例如迭代一些有序且大部分是连续的(没有太多间隙)的 DB ID,是否有一个好的 Rust 哈希映射实现可以与 Java 竞争HashMap或者.NET 的Dictionary?
PS 根据评论中的要求,我在这里粘贴一个示例。我运行了大量测试,但这里有一个简单的示例,在 Rust(发布模式)中需要 75 毫秒,在 Java 中需要 20 毫秒:
在铁锈中:
let hm: FnvHashMap<i32, i32> = ...;
// Start timer here
let mut sum: i64 = 0;
for i in 0..1_000_000 {
if let Some(x) = hm.get(&i) {
sum += …Run Code Online (Sandbox Code Playgroud) lazy_static是一个非常流行的板条箱。几年前,对于某些任务,它没有更好的选择。但今天,还有什么理由选择lazy_static更新的Once_cell或即将推出的LazyLock呢?
为什么 in case of addfunctionmut关键字不是强制的,但 in case ofadd_assign却是强制的?
use std::ops::{Add, AddAssign};
let mut ssa = String::new();
let rr = move || { // no mut for rr is needed
ssa = ssa.add("ds");
println!("{}", ssa);
};
rr();
let mut ssa = String::new();
let mut rr = move || { // mut is mandatory
ssa.add_assign("ds");
println!("{}", ssa);
};
rr();
Run Code Online (Sandbox Code Playgroud) 我正在查看vec![]Rust 中的宏实现,并注意到它使用了__rust_force_expr!宏。这是后者的实现:
/// Force AST node to an expression to improve diagnostics in pattern position.
#[doc(hidden)]
#[macro_export]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
macro_rules! __rust_force_expr {
($e:expr) => {
$e
};
}
Run Code Online (Sandbox Code Playgroud)
有人可以更深入地了解它到底是做什么的吗?
Rust 的默认HashMap哈希器是SipHash,在某些情况下(例如,对于整数)速度要慢得多,但它提供了 HashDoS 保护。如此处所述,它NoHashHasher比默认哈希器快 50 倍,比 FNV 和 FX 哈希器快 10-20 倍(当然,并不总是如此,但在某些情况下,就像那里描述的那样)。
根据我个人的经验,我很少需要针对 HashDoS 攻击的额外保护。例如,如果我将数据库 ID 作为键,并且这些 ID 是基于自动增量的,那么我确实认为那里没有太大风险。尽管如此,我知道有充分的理由将更安全的哈希器作为默认值(安全总比后悔好)。
因此,当我们知道我们不会面临任何 HashDoS 攻击的风险并且需要使用 64 位或更小的整数作为密钥时,是否有任何理由不使用NoHashHasher?显然,性能并不总是更好,而且很明显在某些情况下它甚至可能比 FNV/FX 哈希器表现更差。我特别询问的是在链接问题中描述的情况下需要遵循的不明显的风险、缺点或特殊规则,在这些情况下,很明显NoHashHasher表现出出色的性能。
假设我们有一个函数将相对较大的仅堆栈数据传递给另一个函数,如下所示:
fn a() {
let arr_a: [i32; 1024] = [1, 2, 3, ...];
b(arr_a);
}
fn b(arr_b: [i32; 1024]) {
// ... do stuff with arr_b here
}
Run Code Online (Sandbox Code Playgroud)
用 Rust 术语来说,当b被调用时,asarr_a将被移动到bs中arr_b。在幕后,整个数组是否总是被复制到堆栈上,或者编译器是否有可能通过简单地使用arr_a内存地址处的数据来优化它,而不复制它?如果是后者,编译器的哪一部分应该负责?LLVM?
注意:我知道我们可以保证数组的数据不会通过使用引用/切片来复制,但这不是这个问题的目的。
这是Option的contains()方法签名:
pub const fn contains<U>(&self, x: &U) -> bool
where
U: ~const PartialEq<T>
Run Code Online (Sandbox Code Playgroud)
那到底是什么~const?
rust ×10
hashmap ×2
performance ×2
syntax ×2
compilation ×1
constants ×1
lambda ×1
lazy-static ×1
llvm ×1
macros ×1
traits ×1