我写了一些Rust代码&String
作为参数:
fn awesome_greeting(name: &String) {
println!("Wow, you are awesome, {}!", name);
}
Run Code Online (Sandbox Code Playgroud)
我还编写了代码来引用a Vec
或Box
:
fn total_price(prices: &Vec<i32>) -> i32 {
prices.iter().sum()
}
fn is_even(value: &Box<i32>) -> bool {
**value % 2 == 0
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到一些反馈意见,这样做并不是一个好主意.为什么不?
在编写函数时,如何决定是引用还是使用输入参数?
例如,我应该这样做吗?
fn foo(val: Bar) -> bool { check(val) } // version 1
Run Code Online (Sandbox Code Playgroud)
或者使用引用参数代替?
fn foo(val: &Bar) -> bool { check(*val) } // version 2
Run Code Online (Sandbox Code Playgroud)
在客户端,如果我只有第二个版本但想要消耗我的价值,我必须这样做:
// given in: Bar
let out = foo(&in); // using version 2 but wanting to consume ownership
drop(in);
Run Code Online (Sandbox Code Playgroud)
另一方面,如果我只有第一个版本但想保留我的参考,我必须这样做:
// given in: &Bar
let out = foo(in.clone()); // using version 1 but wanting to keep reference alive
Run Code Online (Sandbox Code Playgroud)
那么哪个是首选,为什么?
做出此选择时是否有任何性能考虑?或者编译器是否使它们在性能方面等效,以及如何实现?
您什么时候想提供两个版本(通过特征)?在那些时候,您如何编写这两个函数的底层实现——您是否复制每个方法签名中的逻辑,或者您是否有一个代理到另一个函数?哪个到哪个,为什么?
我试图迭代地导航递归数据结构,以便在某个位置插入元素.根据我的有限理解,这意味着对结构的根进行可变引用,并通过对其跟随者的引用连续替换它:
type Link = Option<Box<Node>>;
struct Node {
next: Link
}
struct Recursive {
root: Link
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(ref mut node) = *anchor {
anchor = &mut node.next;
}
anchor
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这失败了:
error[E0499]: cannot borrow `anchor.0` as mutable more than once at a time
--> src/main.rs:14:24
|
14 | while let Some(ref mut node) = *anchor {
| ^^^^^^^^^^^^
| | …
Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
fn foo<'a, T: 'a>(t: T) -> Box<Fn() -> &'a T + 'a> {
Box::new(move || &t)
}
Run Code Online (Sandbox Code Playgroud)
我期待的是:
'a
.t
只要有效T
.t
移动到关闭,所以关闭生活只要 t
t
移动到闭包的引用.因此只要闭包存在,引用就是有效的.实际发生了什么:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/lib.rs:2:22
|
2 | Box::new(move || &t)
| ^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 2:14...
--> src/lib.rs:2:14
|
2 | …
Run Code Online (Sandbox Code Playgroud) 我试图理解HashMaps在Rust中是如何工作的,我已经提出了这个例子.
use std::collections::HashMap;
fn main() {
let mut roman2number: HashMap<&'static str, i32> = HashMap::new();
roman2number.insert("X", 10);
roman2number.insert("I", 1);
let roman_num = "XXI".to_string();
let r0 = roman_num.chars().take(1).collect::<String>();
let r1: &str = &r0.to_string();
println!("{:?}", roman2number.get(r1)); // This works
// println!("{:?}", roman2number.get(&r0.to_string())); // This doesn't
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译最后一行未注释的代码时,我收到以下错误
error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277]
println!("{:?}", roman2number.get(&r0.to_string()));
^~~
note: in this expansion of format_args!
note: in this expansion of print! (defined in <std macros>)
note: in this expansion of println! (defined …
Run Code Online (Sandbox Code Playgroud) 我不完全了解生命,但我认为b
生命将在此之前结束self
.
那么,如何编辑这段代码呢?我在内存中复制一些东西吗?如果我创建一个新实例,这个生命周期必须遵循这种情况.
pub struct Formater {
layout: &'static str,
}
impl Formater {
pub fn new(layout: &'static str) -> Formater {
let regex = Regex::new(r"%\{([a-z]+)(?::(.*?[^\\]))?\}").unwrap();
let b = regex.replace_all(layout, "{}");
return Formater {
layout: &b,
};
}
}
Run Code Online (Sandbox Code Playgroud)
错误:
error: `b` does not live long enough
--> src/format.rs:16:22
|
16 | layout: &b,
| ^ does not live long enough
17 | };
18 | }
| - borrowed value only lives until here
|
= …
Run Code Online (Sandbox Code Playgroud) fn main() {
// block1: fails
{
let mut m = 10;
let n = {
let b = &&mut m;
&**b // just returning b fails
};
println!("{:?}", n);
}
// block2: passes
{
let mut m = 10;
let n = {
let b = &&m;
&**b // just returning b fails here too
};
println!("{:?}", n);
}
}
Run Code Online (Sandbox Code Playgroud)
block1因错误而失败:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:7:22
|
7 | let b …
Run Code Online (Sandbox Code Playgroud) 功能数据结构(例如Haskell/Clojure/Scala中使用的Hash Array Mapped Trie)依赖于底层数据结构中的大量共享.例如,如果我们实现insert
类似于地图的数据类型,通常通过在实现数据结构的树上进行路径复制来实现.
鉴于这些数据结构在很大程度上依赖于基础价值的共享(并且没有主要所有者),借款是否会妨碍实施此类结构?
我在这里有两个问题.
let a = [1, 2, 3];
assert_eq!(a.iter().find(|&&x| x == 2), Some(&2));
assert_eq!(a.iter().find(|&&x| x == 5), None);
Run Code Online (Sandbox Code Playgroud)
1.为什么&&x
在闭包参数中使用而不仅仅是x
?(我理解"&"正在传递一个对象的引用,但是两次使用它的意思是什么?)
这本书写道:
因为find()接受引用,并且许多迭代器遍历引用,这导致可能令人困惑的情况,其中参数是双引用.您可以在下面的示例中看到此效果,使用&& x.
但我真的不明白.
2.为什么&
用而不是find()
?
Rust拥有所有权和借贷的概念.如果函数没有将其参数作为引用借用,则该函数的参数将被移动,并且一旦超出范围将被释放.
采取这个功能:
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
}
}
Run Code Online (Sandbox Code Playgroud)
此功能可以称为:
let email = String::from("foo@example.com");
let username = String::from("username");
let user = build_user(email, username);
Run Code Online (Sandbox Code Playgroud)
由于email
与username
已被移动,他们不能再被使用之后build_user
被调用.
这可以通过使API使用借来的引用来修复.
考虑到这一点,在设计API时,哪些场景总是倾向于不使用借用?