我正在做Rust示例教程,其中包含以下代码片段:
// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));
// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter() …Run Code Online (Sandbox Code Playgroud) 我正在浏览“Rust Book”网站,以便学习即将到来的工作面试的语言。在向量章节中,有两个代码示例:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
和:
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想知道,为什么对于第一个样本,当我们将对向量元素i的引用传递到:
println!("{}", i);
但是在我们向向量的每个元素添加 50 的示例中,在添加到 50 之前,我们必须使用 * 取消引用该元素?
我们为什么不/不能做以下事情:
fn main() {
let v = vec![100, 32, 57];
for i in &v {
println!("{}", *i); // why don't we have to dereference before we …Run Code Online (Sandbox Code Playgroud) 我试图了解引用和Box<T>工作方式。让我们考虑一个代码示例:
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
Run Code Online (Sandbox Code Playgroud)
在我的想象中,Rust 将内存中的值保存为:
考虑第二个代码片段Box<T>:
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Run Code Online (Sandbox Code Playgroud)
将如何x存储Box?内存是什么样子的?
上面的例子来自使用DerefTrait处理像常规引用一样的智能指针。对于第二个例子,本书将其解释为:
y示例15-7 和示例15-6 之间的唯一区别是,这里我们设置为指向 in 值的框的实例,x而不是指向 值的引用x。
这是否意味着y在框中直接指向 value 5?
在阅读了方法调用表达式,解引用运算符,方法查找和自动解引用之后,我认为我对该主题有了很好的理解。但是后来我遇到了一种情况,我希望自动重新引用会发生,而实际上却没有发生。
示例如下。
#[derive(Clone, Copy, Debug)]
struct Foo();
impl Into<&'static str> for Foo {
fn into(self) -> &'static str {
"<Foo as Into>::into"
}
}
fn vec_into<F: Copy + Into<T>, T>(slice: &[F]) -> Vec<T> {
slice.iter().map(|x| (*x).into()).collect()
}
fn main() {
let array = [Foo(), Foo(), Foo()];
let vec = vec_into::<_, &'static str>(&array);
println!("{:?}", vec);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码有效,但是我认为不需要(*x).into()在函数中vec_into进行显式取消引用。我的理由是,因为x: &Foo,然后x.into()就试图找到接受类型的方法&Foo,&&Foo,&mut &Foo, …
将 aRc<dyn Trait>作为函数参数传递时,我面临一些奇怪的行为。下面的代码演示了这个问题。
use std::rc::Rc;
trait Trait {}
struct Struct {}
impl Trait for Struct {}
fn function(_t: Rc<dyn Trait>) {}
fn main() {
let n = Rc::new(Struct {});
// ok
let r = Rc::clone(&n);
function(r);
// error, why?
// function(Rc::clone(&n));
}
Run Code Online (Sandbox Code Playgroud)
如果我将 存储Rc在一个临时变量中,则一切正常。但是,如果我尝试Rc::clone在函数调用中直接调用,则会出现以下错误。
use std::rc::Rc;
trait Trait {}
struct Struct {}
impl Trait for Struct {}
fn function(_t: Rc<dyn Trait>) {}
fn main() {
let n = Rc::new(Struct {});
// ok
let r …Run Code Online (Sandbox Code Playgroud) 经过一些讨论,我现在有点困惑之间的关系auto-dereferencing和deref coercion.
似乎 "自动解除引用"一词仅适用于取消引用的目标是方法接收者,而"deref强制"一词似乎适用于函数参数及其所需的所有上下文.
我认为解除引用并不总是涉及deref强制,但我不确定:dereferencing是否始终使用某些Deref::deref特征实现?
如果是这样,是T: Deref<Target = U> where T: &U编译器内置的实现者吗?
最后,在编译器隐式转换&&&&x为的所有情况下,使用术语"autoderef"听起来很自然&x:
pub fn foo(_v: &str) -> bool {
false
}
let x="hello world";
foo(&&&&x);
Run Code Online (Sandbox Code Playgroud)
这是社区的普遍共识吗?
今天的Rust之谜来自The Rust Programming Language,第一版的第4.9节.引用和借用的示例有这个例子:
fn main() {
fn sum_vec(v: &Vec<i32>) -> i32 {
return v.iter().fold(0, |a, &b| a + b);
}
fn foo(v1: &Vec<i32>) -> i32 {
sum_vec(v1);
}
let v1 = vec![1, 2, 3];
let answer = foo(&v1);
println!("{}", answer);
}
Run Code Online (Sandbox Code Playgroud)
这看似合理.它打印出"6",这是你所期望如果
v的sum_vec是一个C++参考; 它只是一个内存位置的名称,v1我们定义的向量main().
然后我sum_vec用这个替换了身体:
fn sum_vec(v: &Vec<i32>) -> i32 {
return (*v).iter().fold(0, |a, &b| a + b);
}
Run Code Online (Sandbox Code Playgroud)
它按预期编译和工作.好吧,那不是......完全疯了.编译器试图让我的生活更轻松,我明白了.令人困惑的是,我必须记住这个语言的特定时态,但并不完全是疯狂的.然后我尝试了:
fn sum_vec(v: &Vec<i32>) -> i32 {
return (**v).iter().fold(0, |a, &b| …Run Code Online (Sandbox Code Playgroud) 为什么Send在特征实现中忽略自动特征的特征边界?(游乐场(1))
trait IsSend {
fn is_send(&self);
}
impl<T: Send> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // (!!) no compiler error although Rc<...> is not Send
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
例如,使用绑定到自定义特征(X)的特征可以工作:(Playground(2))
trait X {}
trait IsSend {
fn is_send(&self);
}
impl<T: X> IsSend for T {
fn is_send(&self) {}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let i = std::rc::Rc::new(43);
i.is_send(); // …Run Code Online (Sandbox Code Playgroud) 有人可以解释一下,根据匹配人体工程学规则(RFC 2005) ,在参考模式中使用单个值如何出现 两次取消引用匹配值的情况?&
假设我们有一个map: HashMap<i32, bool>. 考虑表达式map.iter().filter(|entry| ...),其中 的类型entry为&(&i32, &bool)。entry现在,如果我们通过以下两种方式进行模式匹配会怎么样?
map
.iter()
.filter(|entry| {
let (key1, _) = entry; // typeof(key1) -> &&i32
let (&key2, _) = entry; // typeof(key2) -> i32
})
Run Code Online (Sandbox Code Playgroud)
据我了解,这两种模式都使用非引用模式匹配引用(对元组),因此将默认绑定模式更改为ref. 但令我困惑的是 类型key2最终是 asi32和 not &i32。
根据 RFC 2005,这里尝试编写上述两种模式的脱糖模式:
let &(ref key1_desugared, _) = entry; // typeof(key1_desugared) -> &&i32
let &(& ref key2_desugared, _) …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 ×10
dereference ×4
generics ×1
pointers ×1
reference ×1
string ×1
terminology ×1
traits ×1