怎样修改静态公司网站页面电话,wordpress翻译公司,网站地图分析工具,洛阳建设三轮网站1. 引用与借用 下面的示例重新定义了一个新的 calculate_length 函数。与之前不同的是#xff0c;新的函数签名使用了 String 的引用作为参数而没有直接转移值的所有权#xff1a;
fn main() { let s1 String::from(hello); let len calculate_length(s1…1. 引用与借用 下面的示例重新定义了一个新的 calculate_length 函数。与之前不同的是新的函数签名使用了 String 的引用作为参数而没有直接转移值的所有权
fn main() { let s1 String::from(hello); let len calculate_length(s1); println!(The length of {} is {}., s1, len);
} fn calculate_length(s: String) - usize { s.len()
} 首先需要注意的是变量声明及函数返回值中的那些元组代码都消失了。其次我们在调用 calculate_length 函数时使用了 s1 作为参数且在该函数的定义中我们使用 String 替代了 String。 这些 代表的就是引用语义它们允许你在不获取所有权的前提下使用值。下图所展示的是该过程的一个图解。 图1String s指向String s1的图解 注意 与使用 进行引用相反的操作被称为解引用dereferencing它使用 * 作为运算符。这个我们后面文章中会详细讨论。 现在让我们仔细观察一下这个函数的调用过程
let s1 String::from(hello);let len calculate_length(s1); 这里的 s1 语法允许我们在不转移所有权的前提下创建一个指向 s1 值的引用。由于引用不持有值的所有权所以当引用离开当前作用域时它指向的值也不会被丢弃。 同理函数签名中的 用来表明参数 s 的类型是一个引用。下面的注释给出了更详细的解释
fn calculate_length(s: String) - usize { // s 是一个指向 String 的引用s.len()
} // 到这里s离开作用域。但是由于它并不持有自己所指向值的所有权
//所以没有什么特殊的事情会发生 此处变量 s 的有效作用域与其他任何函数参数一样唯一不同的是它不会在离开自己的作用域时销毁其指向的数据因为它并不拥有该数据的所有权。 当一个函数使用引用而不是值本身作为参数时我们便不需要为了归还所有权而特意去返回值毕竟在这种情况下我们根本没有取得所有权。这种通过引用传递参数给函数的方法也被称为借用borrowing。 在现实生活中假如一个人拥有某件东西你可以从他那里把东西借过来。但是当你使用完毕时就必须将东西还回去。如果我们尝试着修改借用的值又会发生什么呢我们来运行下面的代码测试一下。剧透这段代码无法通过编译
fn main() { let s String::from(hello); change(s);
} fn change(some_string: String) { some_string.push_str(, world);
} 报错内容如下
error[E0596]: cannot borrow immutable borrowed content
*some_string as mutable-- error.rs:8:5|
7 | fn change(some_string: String) {| ------- use mut String here to make mutable
8 | some_string.push_str(, world);| ^^^^^^^^^^^ cannot borrow as mutable 与变量类似引用是默认不可变的Rust不允许我们去修改引用指向的值。 2. 可变引用 我们可以通过进行一个小小的调整来修复上面代码中出现的编译错误
fn main() { let mut s String::from(hello); change(mut s);
} fn change(some_string: mut String) { some_string.push_str(, world);
} 首先我们需要将变量 s 声明为 mut即可变的。其次我们使用 mut s 来给函数传入一个可变引用并将函数签名修改为 some_string: mut String 来使其可以接收一个可变引用作为参数。 但可变引用在使用上有一个很大的限制对于特定作用域中的特定数据来说一次只能声明一个可变引用。以下代码尝试违背这一限制则会导致编译错误
let mut s String::from(hello); let r1 mut s;
let r2 mut s; 出现的错误如下所示
error[E0499]: cannot borrow s as mutable more than once at a time-- borrow_twice.rs:5:19|
4 | let r1 mut s;| - first mutable borrow occurs here
5 | let r2 mut s;| ^ second mutable borrow occurs here
6 | }| - first borrow ends here 这个规则使得引用的可变性只能以一种受到严格限制的方式来使用。许多刚刚接触Rust的开发者会反复地与它进行斗争因为大部分的语言都允许你随意修改变量。 但另一方面在Rust中遵循这条限制性规则可以帮助我们在编译时避免数据竞争。数据竞争data race与竞态条件十分类似它会在指令满足以下3种情形时发生 两个或两个以上的指针同时访问同一空间。 其中至少有一个指针会向空间中写入数据。 没有同步数据访问的机制。 数据竞争会导致未定义的行为由于这些未定义的行为往往难以在运行时进行跟踪也就使得出现的 bug 更加难以被诊断和修复。 Rust则完美地避免了这种情形的出现因为存在数据竞争的代码连编译检查都无法通过与大部分语言类似我们可以通过花括号来创建一个新的作用域范围。 这就使我们可以创建多个可变引用当然这些可变引用不会同时存在
let mut s String::from(hello);{let r1 mut s;} // 由于 r1 在这里离开了作用域所以我们可以合法地再创建一个可变引用。let r2 mut s; 在结合使用可变引用与不可变引用时还有另外一条类似的限制规则它会导致下面的代码编译失败 出现的错误如下所示 哇发现了吗我们不能在拥有不可变引用的同时创建可变引用。不可变引用的用户可不会希望他们眼皮底下的值突然发生变化 不过同时存在多个不可变引用是合理合法的对数据的只读操作不会影响到其他读取数据的用户。 尽管这些编译错误会让人不时地感到沮丧但是请牢记这一点Rust编译器可以为我们提早在编译时而不是运行时暴露那些潜在的 bug并且明确指出出现问题的地方。你不再需要去追踪调试为何数据会在运行时发生了非预期的变化。 3. 悬垂引用 使用拥有指针概念的语言会非常容易错误地创建出悬垂指针。这类指针指向曾经存在的某处内存地址但该内存已经被释放掉甚至是被重新分配另作他用了。 而在Rust语言中编译器会确保引用永远不会进入这种悬垂状态。假如我们当前持有某个数据的引用那么编译器可以保证这个数据不会在引用被销毁前离开自己的作用域。 让我们试着来创建一个悬垂引用并看一看Rust是如何在编译期发现这个错误的
fn main() { let reference_to_nothing dangle();
} fn dangle() - String { let s String::from(hello); s
} 出现的错误如下所示
error[E0106]: missing lifetime specifier-- dangle.rs:5:16|
5 | fn dangle() - String {| ^ expected lifetime parameter| help: this functions return type contains a borrowed value, but there isno value for it to be borrowed from help: consider giving it a static lifetime 这段错误提示信息包含了一个我们还没有接触到的新概念生命周期我们会在后文详细讨论。不过即使我们先将生命周期放置不管这条错误提示信息也准确地指出了代码中的问题 this functions return type contains a borrowed value, but there is no valuefor it to be borrowed from.[1] 译文此函数的返回类型包含一个借用的值但没有可供借用的值。[1] 回过头来仔细看一看我们的dangle函数中究竟发生了些什么
fn dangle() - String { // dangle会返回一个指向String的引用let s String::from(hello); // s被绑定到新的String上 s // 我们将指向s的引用返回给调用者
} // 变量s在这里离开作用域并随之被销毁它指向的内存自然也不再有效。 // 危险 由于变量 s 创建在函数 dangle 内所以它会在 dangle 执行完毕时随之释放。 但是我们的代码依旧尝试返回一个指向 s 的引用这个引用指向的是一个无效的 String这可不对 Rust成功地拦截了我们的危险代码。解决这个问题的方法也很简单直接返回 String 就好
fn no_dangle() - String { let s String::from(hello); s
} 这种写法没有任何问题所有权被转移出函数自然也就不会涉及释放操作了。 4. 引用的规则 让我们简要地概括一下本篇文章对引用的讨论 在任何一段给定的时间里你要么只能拥有一个可变引用要么只能拥有任意数量的不可变引用。 引用总是有效的。
下篇文章中继续讨论另外一种特殊的引用形式切片。