为啥我可以在嵌套函数 (Rust) 中有多个 &mut 引用?

     2023-02-18     106

关键词:

【中文标题】为啥我可以在嵌套函数 (Rust) 中有多个 &mut 引用?【英文标题】:Why am I allowed to have multiple &mut refs in nested functions (Rust)?为什么我可以在嵌套函数 (Rust) 中有多个 &mut 引用? 【发布时间】:2022-01-16 15:57:17 【问题描述】:

我是 rust 新手,想知道为什么下面的代码不会导致: 不能一次多次将 val 借用为 mutable 错误。似乎当我到达 second_layer 函数时,我应该对同一个原始 val 变量有三个单独的引用:

主函数体中的val_ref

first_layer函数体中的val_ref2

第二层函数体中的val_ref3

任何帮助将不胜感激!

fn first_layer(val_ref2: &mut String)

    *val_ref2 = String::from("first_layer");
    println!("", val_ref2);
    second_layer(val_ref2);


fn second_layer(val_ref3: &mut String)

    *val_ref3 = String::from("second_layer");
    println!("", val_ref3);



fn main()

    let mut val = String::from("asdf");
    let val_ref: &mut String = &mut val;

    first_layer(val_ref);

    println!("", val_ref);


谢谢,

【问题讨论】:

这是由于隐式重借。请看看这个post。 @Joe_Jingyu 允许嵌套引用存在的不是重借,而是相反 - 允许重借的是嵌套引用(显式 隐式)。这个问题似乎在问为什么允许嵌套引用的别名开始,而链接的答案没有解决这个问题。 感谢您的 cmets,@user4815162342。我不清楚为什么您认为链接的帖子没有解决此案。不是因为reborrow,val-refmain 中调用first_layer 后仍然可以访问吗? @Joe_Jingyu 因为这里的提问者询问嵌套引用如何开始,而不管隐式重借。换句话说,当let mut i = 0i32; let r1 = &mut i; let r2 = &mut *r1 显然创建了对i 的别名可变引用时,为什么还要编译呢?隐式重借的讨论并未涵盖这一点,因为它只是解释了隐式重借如何通过创建嵌套引用来防止引用被移动。它没有解释为什么允许嵌套的内部引用对外部引用的数据进行别名。 @user4815162342 我明白你的意思。但是,我不知道RFC#2094 是否是关于重新借用动机的好文档。如果你知道一个更适合初学者。我也很想读书。谢谢。 【参考方案1】:

在函数调用期间暂时不存在调用另一个函数的函数中的引用。

标识符不会自动存在于堆栈下方调用的函数中。仅仅因为一个函数调用另一个函数并不意味着被调用者应该有权访问调用者的局部变量。如果你尝试过,你会得到一个not found in this scope

可以(尝试)做的是创建一个闭包来捕获调用者的环境,然后重用调用者的变量之一。但是如果你违反了借用规则,你会发现编译器会报错。

fn first_layer(val_ref2: &mut String) 
    // println!("", val); // Cannot use val from main!
    *val_ref2 = String::from("first_layer");
    println!("", val_ref2);
    (|val_ref3: &mut String| 
        *val_ref3 = String::from("second_layer");
        println!("", val_ref3);
        println!("", val_ref2); // This is not allowed
    )(val_ref2);


fn main() 
    let mut val = String::from("asdf");
    let val_ref: &mut String = &mut val;

    first_layer(val_ref);

    println!("", val_ref);

另一种思考方式是内联。如果你将你的函数 second_layer 内联到 first_layer 你会得到:

fn first_layer(val_ref2: &mut String)

    *val_ref2 = String::from("first_layer");
    println!("", val_ref2);
    *val_ref2 = String::from("second_layer");
    println!("", val_ref2);

这完全没问题!

那么最后两行代码抽象成自己的函数也应该没问题。

【讨论】:

请注意,您还可以在同一函数中创建对同一数据的两个可变引用,例如let mut i = 0i32; let r1 = &mut i; let r2 = &mut *r1;. @user4815162342,如果你尝试使用它们,你会得到一个错误:fn main() let mut i = 0; let r1 = &mut i; let r2 = &mut *r1; *r1 += 1; *r2 += 1; 使用r2不会报错,只有在r2被删除后才使用r1。但这并不能否定为什么 Rust 一开始就允许它们存在的问题。我相信原因是:1)允许重新借用,2)允许预测,即获得对您所引用的部分数据的可变引用。嵌套引用是投影的一种特殊情况。

为啥我可以在结构的类型参数中编写函数类型?

】为啥我可以在结构的类型参数中编写函数类型?【英文标题】:WhyamIabletowriteafunctiontypeinthetypeparameterofastruct?为什么我可以在结构的类型参数中编写函数类型?【发布时间】:2021-12-2506:40:42【问题描述】:如果我理解正确的话... 查看详情

c语言中函数为啥可以嵌套定义?

取决于编译器.我在Ubuntu16.04用默认gcc,在eclipse中测试可以实现嵌套定义.经测试在函数中定义的函数,在当前作用域可以被调用.这样一来,c语言貌似具有了一些面向对象的特性,使用起来比较方便参考技术AC语言中函数的定义都是相... 查看详情

为啥 C/RUST 中的一个加法计算在结果 ASM 中有 3 个双精度浮点加法工具?

】为啥C/RUST中的一个加法计算在结果ASM中有3个双精度浮点加法工具?【英文标题】:WhyoneaddcalcuationinC/RUSThas3double-precisionfloating-pointaddinstrumentsinresultASM?为什么C/RUST中的一个加法计算在结果ASM中有3个双精度浮点加法工具?【发布... 查看详情

为啥 Rust 在 main 函数中没有返回值,以及如何返回值?

】为啥Rust在main函数中没有返回值,以及如何返回值?【英文标题】:WhydoesRustnothaveareturnvalueinthemainfunction,andhowtoreturnavalueanyway?为什么Rust在main函数中没有返回值,以及如何返回值?【发布时间】:2014-08-0608:55:15【问题描述】:... 查看详情

为啥在 BigQuery 中取消嵌套两个或多个变量时没有得到任何结果?

】为啥在BigQuery中取消嵌套两个或多个变量时没有得到任何结果?【英文标题】:WhywhenunnestingtwoormorevariablesinBigQuerydoIgetnoresults?为什么在BigQuery中取消嵌套两个或多个变量时没有得到任何结果?【发布时间】:2017-05-1811:00:43【问... 查看详情

为啥我可以在成员函数中使用尚未声明的成员变量?

】为啥我可以在成员函数中使用尚未声明的成员变量?【英文标题】:WhycanIuseanas-of-yetundeclaredmembervariableinamemberfunction?为什么我可以在成员函数中使用尚未声明的成员变量?【发布时间】:2017-02-2409:29:19【问题描述】:例如:str... 查看详情

为啥我不能在 Laravel 上正确映射嵌套查询? “在 null 上调用成员函数 map()”显示为错误

】为啥我不能在Laravel上正确映射嵌套查询?“在null上调用成员函数map()”显示为错误【英文标题】:Whycan\'tIproperlymapnestedqueryonLaravel?"Calltoamemberfunctionmap()onnull"shownaserror为什么我不能在Laravel上正确映射嵌套查询?“在null... 查看详情

为啥在终端中没有 getch() 就看不到 hello world 的输出;虽然我可以使用 memcpy() 函数查看多个 printf 吗?

】为啥在终端中没有getch()就看不到helloworld的输出;虽然我可以使用memcpy()函数查看多个printf吗?【英文标题】:WhyIcannotseetheoutputofhelloworldwithoutgetch()interminal;whileIcanseeformultipleprintfwithmemcpy()function?为什么在终端中没有getch()就看不... 查看详情

为啥 Rust 函数和 FFI C++ 函数以相反的顺序执行?

】为啥Rust函数和FFIC++函数以相反的顺序执行?【英文标题】:WhydoaRustfunctionandaFFIC++functionexecuteinreverseorder?为什么Rust函数和FFIC++函数以相反的顺序执行?【发布时间】:2018-03-2511:13:09【问题描述】:我尝试将外部C++函数与我的Rus... 查看详情

为啥这两个非常相似的异步 Rust 函数之一会触发线程安全错误?

】为啥这两个非常相似的异步Rust函数之一会触发线程安全错误?【英文标题】:WhydoesoneofthesetwoverysimilarasyncRustfunctionstriggerthreadsafetyerrors?为什么这两个非常相似的异步Rust函数之一会触发线程安全错误?【发布时间】:2021-12-1003:... 查看详情

如何创建一个在猪中有嵌套包的输出模式

...如下。例如,我正在分析电子商务订单数据。一个订单中可以订购多个产品。我有按订单级别分组的产品级别 查看详情

为啥嵌套函数可以从外部函数访问变量,但不允许修改它们[重复]

】为啥嵌套函数可以从外部函数访问变量,但不允许修改它们[重复]【英文标题】:Whynestedfunctionscanaccessvariablesfromouterfunctions,butarenotallowedtomodifythem[duplicate]为什么嵌套函数可以从外部函数访问变量,但不允许修改它们[重复]【发... 查看详情

为啥在嵌套函数之外声明一个计数器变量会使循环慢 5 倍?

】为啥在嵌套函数之外声明一个计数器变量会使循环慢5倍?【英文标题】:Whydoesdeclaringacountervariableoutsideofanestedfunctionmakealoop5xslower?为什么在嵌套函数之外声明一个计数器变量会使循环慢5倍?【发布时间】:2018-03-1409:00:38【问... 查看详情

为啥我的函数在严格模式(函数形式)下未定义?

】为啥我的函数在严格模式(函数形式)下未定义?【英文标题】:Whydoesmyfunctiongetundefinedinstrictmode(functionform)?为什么我的函数在严格模式(函数形式)下未定义?【发布时间】:2018-08-1720:42:08【问题描述】:基本上我的页面中... 查看详情

为啥不能在多个函数中定义相同的本地标签?

】为啥不能在多个函数中定义相同的本地标签?【英文标题】:whycannotdefinesamelocallabelinmultiplefunctions?为什么不能在多个函数中定义相同的本地标签?【发布时间】:2017-01-2820:43:24【问题描述】:想在多个函数中定义相同的局部... 查看详情

为啥 Rust 认为我的私有类型必须是公共的,除非我使用 pub(crate)?

】为啥Rust认为我的私有类型必须是公共的,除非我使用pub(crate)?【英文标题】:WhydoesRustthinkmyprivatetypemustbepublicunlessIusepub(crate)?为什么Rust认为我的私有类型必须是公共的,除非我使用pub(crate)?【发布时间】:2021-04-2117:04:29【问... 查看详情

gcc 编译错误:模板类表中嵌套类 A ​​的成员在嵌套朋友类中不可见。为啥?

...模板类表中嵌套类A​​的成员在嵌套朋友类中不可见。为啥?【英文标题】:gcccompilingerror:memberofnestedclassAintemplateclassTableisnotvisibleinnestedfriendclass.Why?gcc编译错误:模板类表中嵌套类A​​的成员在嵌套朋友类中不可见。为什么?... 查看详情

是否可以从将引用作为参数的 rust dll 导出函数

】是否可以从将引用作为参数的rustdll导出函数【英文标题】:Isitpossibletoexportafunctionfromrustdllwhichtakesareferenceasaparameter【发布时间】:2021-07-0418:52:53【问题描述】:我是学习rust的新手,我看到rust使用通用生命周期在编译时验证引... 查看详情