我写了以下内容来测试闭包:
fn main() {
let captured_val = "a captured value".to_string();
let closure_parameter = "a parameter value".to_string();
let mut ct = ClosureTest {
cls: |closure_parameter| &captured_val,
};
println!("{}", (ct.cls)(&closure_parameter));
}
struct ClosureTest<T>
where
T: FnMut(&str) -> &str,
{
cls: T,
}
我收到了以下编译错误:
error[E0373]: closure may outlive the current function, but it borrows `captured_val`, which is owned by the current function
--> src/main.rs:6:14
|
6 | cls: |closure_parameter| &captured_val,
| ^^^^^^^^^^^^^^^^^^^ ------------ `captured_val` is borrowed here
| |
| may outlive borrowed value `captured_val`
help: to force the closure to take ownership of `captured_val` (and any other referenced variables), use the `move` keyword
|
6 | cls: move |closure_parameter| &captured_val,
| ^^^^^^^^^^^^^^^^^^^^^^^^
我在struct中添加了一个生命周期参数,它编译并运行良好:
struct ClosureTest<'a, T>
where
T: FnMut(&str) -> &'a str,
{
cls: T,
}
两个变量(captured_val
和closure_parameter
)都在同一范围内,但似乎编译器没有看到它们具有相同的生命周期而没有添加生命周期参数'a
到ClosureTest<T>
。这是因为Rust的封闭期终生推断?
我不理解我收到的错误消息中的第一行:
error[E0373]: closure may outlive the current function, but it borrows `captured_val`, which is owned by the current function
封闭怎么能比现在的功能更长久?闭包是在当前函数中定义的,所以我认为闭包将在当前函数的末尾消失。
错误消息的真正含义是什么?为什么通过像我一样添加生命周期参数来解决?
答案 0 :(得分:1)
简短版本:添加显式生命周期注释会使{strong>保证约为ClosureTest
,如果没有它,则不一定暗示。
假设你这样做了:
fn main() {
let closure_parameter = "a parameter value".to_string();
let returned_ct = do_something(v);
println!("{}", (returned_ct.cls)(&closure_parameter));
}
fn do_something() -> ClosureTest {
let captured_val = "a captured value".to_string();
let mut ct = ClosureTest {
cls: |param| &captured_val,
};
ct // !!!
}
struct ClosureTest<T>
where
T: FnMut(&str) -> &str,
{
cls: T,
}
在标有!!!
的行上,请注意ct
已移动作为返回值。现在的对象是“生活”。在main
中,但它包含对do_something
结束时删除的内容的引用。 ct.cls
正在将引用返回给captured_val
,如果将ct
移出该功能,该引用将不再存在。
通过修改ClosureTest
以包含生命周期,您将说明以下内容:
ClosureTest
对象obj
有一些生命周期'a
str
返回的obj.cls
引用的有效期为'a
obj
,obj.cls
ClosureTest
返回的任何引用都与返回它的obj
具有相同的范围。 ClosureType<'a, T> where T: FnMut(&str) -> &'a str
将与其闭包引用的对象或更早同时删除。换句话说,任何T
只能在对象ct
的返回引用存在时生存,并且在删除该对象时必须删除。借用检查程序不会因原始值而烦恼,因为captured_value
和captured_val
的生命周期不同,因为他们可能有不同的生命时间 - 因此&#39;可能&#39;在&#39;中可能比借来的价值captured_val
更长久。当您在示例中添加lifetime参数时,借用检查器现在可以确认它只应在ct
和main
一样长的时间内进行编译,它会在String orgWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
ArrayList<ContentProviderOperation> opsUpdate = new ArrayList<>();
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneTextInputLayout.getEditText().getText().toString())
.build());
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, emailTextInputLayout.getEditText().getText().toString())
.build());
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Website.URL, websiteTextInputLayout.getEditText().getText().toString())
.build());
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Note.NOTE, notesTextInputLayout.getEditText().getText().toString())
.build());
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, nameTextInputLayout.getEditText().getText().toString())
.build());
if (professionTextInputLayout2.getEditText().getText().toString().isEmpty()){
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Organization.DATA4, professionTextInputLayout.getEditText().getText().toString())
.build());
} else {
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.Organization.DATA4, professionTextInputLayout.getEditText().getText().toString() + "/" + professionTextInputLayout2.getEditText().getText().toString())
.build());
}
opsUpdate.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(orgWhere, new String[]{String.valueOf(contactID), ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE})
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, locationTextInputLayout.getEditText().getText().toString())
.build());
try {
ContentProviderResult[] res = this.getContentResolver().applyBatch(
ContactsContract.AUTHORITY, opsUpdate);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
结束时删除它们(它们都在{ {1}})。