关于静态和动态调度的生锈书部分中有关于此主题的一些基本背景,但tldr基本上是:在特征引用上调用方法和其他一些不同的情况(函数指针等)导致动态而不是静态调度.
所以,问题:
在应用优化后,实际的运行时成本是多少?
例如,想象一下这组结构和特征:
struct Buffer;
struct TmpBuffer;
struct TmpMutBuffer;
impl BufferType for Buffer { ... }
impl BufferType for BufferTmp { ... }
impl BufferType for BufferTmpMut { ... }
impl Buffer2D for BufferType { ... }
impl Buffer2DExt for Buffer2D { ... }
Run Code Online (Sandbox Code Playgroud)
特别注意,这里的特征是在特征本身上实现的.
在struct reference上从Buffer2DExt调用方法的动态调度的调用成本是多少?
最近有一个关于解除引用规则的问题这是什么是Rust的确切自动解除引用规则?; 这些规则是在编译时还是运行时应用的?
我有一个结构,主要封装了一个向量:
struct Group<S> {
elements: Vec<S>
}
Run Code Online (Sandbox Code Playgroud)
我也有一个简单的特征,该特征也可用于其他结构:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}
Run Code Online (Sandbox Code Playgroud)
我想实现Solid的Group,但我希望能够使用Group都为相同的实现的名单Solid和混合实现的名单Solid。基本上我想同时使用Group<Box<Solid>>和Group<Sphere>(Sphere实现Solid)。
目前我正在使用这样的东西:
impl Solid for Group<Box<Solid>> {
fn intersect(&self, ray: f32) -> f32 {
//do stuff
}
}
impl<S: Solid> Solid for Group<S> {
fn intersect(&self, ray: f32) -> f32 {
//do the same stuff, code copy-pasted from previous impl
}
}
Run Code Online (Sandbox Code Playgroud)
这是可行的,但是两次换行相同的代码不是惯用的解决方案。我一定缺少明显的东西吗?
就我而言,我测量了两个特征实现之间的显着性能差异,因此始终使用 …
这段代码:
fn main() {
let s = "hello".to_string();
let keywords = vec!["hello", "bye"];
// if keywords.contains(&s.as_str())
if keywords.contains(&&s)
// ~> expected &&str, found &collections::string::String
{
println!("exists");
}
}
Run Code Online (Sandbox Code Playgroud)
通常,当函数期望&str类型时,你可以给一个String
let s = "abc".to_string();
foo(&s); // ok,
Run Code Online (Sandbox Code Playgroud)
但是&&s不DEREF来&&str,我认为这是不一致的.
我读过什么是Rust的确切自动解除引用规则?从头到尾,但我仍然有一个关于从数组到切片的强制的问题.
让我们考虑以下代码:
let arr: &[i32; 5] = &&&[1, 2, 3, 4, 5];
// let arr: &[i32] = &&&[1, 2, 3, 4, 5]; // Error; expected slice, found reference
Run Code Online (Sandbox Code Playgroud)
我希望它&&&[1, 2, 3, 4, 5]有类型,&&&[i32; 5]并且引用 &&[i32; 5]=> &[i32; 5]=> &[i32; 5]=> &[i32],但结果与我的预期不同.
我试着运行以下代码:
let arr: &&&[i32; 5] = &&&[1, 2, 3, 4, 5];
let n = arr.first().unwrap(); // 1
Run Code Online (Sandbox Code Playgroud)
这是正确的代码.arr强制类型为&&&[i32; 5]=> &&[i32; 5]=> &[i32; 5]=> …
我以前觉得这和C++中的lvalue reference collapsing很像,所以从语法上&&T应该和,一样&T,但是我编译了下面的代码后就糊涂了:
fn check_ref(x: &i32) -> i32 {
println!("{}", x);
x + 2
}
fn main() {
for i in &[-3, 2, 39] {
// i is &i32
check_ref(i); // this works
check_ref(&i); // this works
check_ref(&&i); // this works
assert_eq!(i, &i); // error[E0277]: can't compare `i32` with `&i32`
}
}
Run Code Online (Sandbox Code Playgroud)
多个引用是否会崩溃,或者 ref-to-ref 是否有其他特定含义?
这个编译器错误assert_eq!仅仅是因为 Rust 宏中的一些技巧吗?
当尝试在 rust 中实现双链表时,我发现以下意外错误
if let Some(link) = self.tail.take() {
let x = link.borrow_mut();
link.borrow_mut().next = Some(node.clone());
} else { ... }
Run Code Online (Sandbox Code Playgroud)
这里链接被推断为Rc<RefCell<Node<..>>>和编译器说:
不能将不可变的局部变量借用
link为可变的。
试过之后,我猜是什么时候use std::borrow::BorrowMut,错误发生了。
// compiles
fn test1() {
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
// doesn't compile
fn test2() {
use std::borrow::BorrowMut; // inserted this import!
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
Run Code Online (Sandbox Code Playgroud)
这里test2()编译失败。我想知道为什么它会这样工作。
我注意到Microsoft 的 Take your first steps with Rust 中的代码:
fn count_letters(text: &str) -> usize {
text.chars().filter(|ref c| c.is_alphabetic()).count()
}
Run Code Online (Sandbox Code Playgroud)
很明显,没有ref.
为什么ref用在这里?我应该什么时候使用ref?这里有什么惯用的编程实践吗?
我想实现一个函数,它接受不可变的&Vec引用,制作副本,对值进行排序并打印它们。
这是主要代码。
trait Foo {
fn value(&self) -> i32;
}
struct Bar {
x: i32,
}
impl Foo for Bar {
fn value(&self) -> i32 {
self.x
}
}
fn main() {
let mut a: Vec<Box<dyn Foo>> = Vec::new();
a.push(Box::new(Bar { x: 3 }));
a.push(Box::new(Bar { x: 5 }));
a.push(Box::new(Bar { x: 4 }));
let b = &a;
sort_and_print(&b);
}
Run Code Online (Sandbox Code Playgroud)
我能够让它发挥作用的唯一方法就是这个
fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
let mut v_copy = Vec::new();
for val in v {
v_copy.push(val);
} …Run Code Online (Sandbox Code Playgroud) use std::ops::Add;
#[derive(Debug)]
struct Sample {
pub value: usize,
}
impl std::ops::Add<&Sample> for &Sample {
type Output = Sample;
fn add(self, other: &Sample) -> Sample {
Sample {
value: self.value + other.value,
}
}
}
fn main() {
let mut a = Sample { value: 0 };
let b = Sample { value: 1 };
let mut_a = &mut a;
let immut_b = &b;
println!("Works: {:?}", mut_a.add(immut_b));
println!("And this works: {:?}", immut_b.add(mut_a));
println!("Also works:: {:?}", immut_b + mut_a);
println!("Still works:: …Run Code Online (Sandbox Code Playgroud) 如何理解下面这段代码?我是Rust的新手,但有C/Haskell背景和一点点C++.我能找到的唯一参考是减轻强制.
fn main() {
let xs: [u32; 4] = [0, 1, 2, 3];
let mut i: u32 = 0;
for x in xs.iter() {
if i > *x { // It looks x is an iterator. Understood.
i = i + x; // no error. (coerced)
//Quote: "Rust will do this as many times
// as possible until the types match."
i = i + *x; // no error (explicit deref)
i += x; // error about u32/&u32 …Run Code Online (Sandbox Code Playgroud)