如何 return 当 ref 和所有权转移都不起作用时
How to return when ref and ownership transfer both won't work
所以,如果我 return 这个
self.string_ref.unwrap().as_ref()
编译器会说
error[E0515]: cannot return value referencing temporary value
returns a value referencing data owned by the current function
如果我return这个
*self.string_ref.unwrap().as_ref()
编译器会说
error[E0507]: cannot move out of borrowed content
这简直让我抓狂
代码如下:(playground)
use std::ptr::NonNull;
struct A {
string_ref: Option<NonNull<String>>,
}
struct Number {
num: i32
}
impl A {
fn hello() {
}
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
fn main() {
let a = A {
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
};
let t = a.give_me_string();
println!("{}", t)
}
将您的示例剥离到最低限度:
struct A {
string_ref: Option<NonNull<String>>,
}
impl A {
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
这里有一些错误:
- 最明显的一个是您试图取得
self.string_ref
的所有权,即使您只是借用了 self
。
要解决这个问题,您需要使用 match
语句,它允许您解构 self.string_ref
而不是使用它:
fn give_me_string(&self) -> String {
unsafe {
match self.string_ref {
Some(x) => x.as_ref(),
None => panic!("Had no `string_ref`!")
}
}
}
as_ref
returns &T
,所以你不能 return 一个拥有的字符串,相反你需要克隆它然后 return 一个拥有的字符串,或者引用它:
//Option one: Clone contents
match self.string_ref {
Some(ref x) => x.as_ref().clone(),
_ => //...
}
//Option two: Return reference.
fn give_me_string(&self) -> &str {
unsafe {
match &self.string_ref {
Some(x) => x.as_ref() as _,
_ => //...
}
}
}
为了解决评论中提到的另一个问题,您的 main
函数中有以下语句:
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
由于其性质,这将导致 UB
。您正在使用 String::from
形成 String
,但并未将其值存储在任何地方,而是立即转换为指针。这将释放行尾的 String
,导致 UB
.
多亏了@Optimistic Peach
,所以我基本上弄明白了是怎么回事
fn give_me_string(&self) -> &String {
unsafe {
match self.string_ref {
Some(x) => &*(x.as_ptr() as *const _), //without ref
Some(ref x) => x.as_ptr(), // with ref
None => panic!("hello?")
}
}
}
所以,如果我 return 这个
self.string_ref.unwrap().as_ref()
编译器会说
error[E0515]: cannot return value referencing temporary value
returns a value referencing data owned by the current function
如果我return这个
*self.string_ref.unwrap().as_ref()
编译器会说
error[E0507]: cannot move out of borrowed content
这简直让我抓狂
代码如下:(playground)
use std::ptr::NonNull;
struct A {
string_ref: Option<NonNull<String>>,
}
struct Number {
num: i32
}
impl A {
fn hello() {
}
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
fn main() {
let a = A {
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
};
let t = a.give_me_string();
println!("{}", t)
}
将您的示例剥离到最低限度:
struct A {
string_ref: Option<NonNull<String>>,
}
impl A {
fn give_me_string(&self) -> String {
unsafe {
*self.string_ref.unwrap().as_ref()
}
}
}
这里有一些错误:
- 最明显的一个是您试图取得
self.string_ref
的所有权,即使您只是借用了self
。
要解决这个问题,您需要使用match
语句,它允许您解构self.string_ref
而不是使用它:
fn give_me_string(&self) -> String {
unsafe {
match self.string_ref {
Some(x) => x.as_ref(),
None => panic!("Had no `string_ref`!")
}
}
}
as_ref
returns&T
,所以你不能 return 一个拥有的字符串,相反你需要克隆它然后 return 一个拥有的字符串,或者引用它:
//Option one: Clone contents
match self.string_ref {
Some(ref x) => x.as_ref().clone(),
_ => //...
}
//Option two: Return reference.
fn give_me_string(&self) -> &str {
unsafe {
match &self.string_ref {
Some(x) => x.as_ref() as _,
_ => //...
}
}
}
为了解决评论中提到的另一个问题,您的 main
函数中有以下语句:
string_ref: NonNull::new(&mut String::from("hello world") as *mut String)
由于其性质,这将导致 UB
。您正在使用 String::from
形成 String
,但并未将其值存储在任何地方,而是立即转换为指针。这将释放行尾的 String
,导致 UB
.
多亏了@Optimistic Peach
,所以我基本上弄明白了是怎么回事fn give_me_string(&self) -> &String {
unsafe {
match self.string_ref {
Some(x) => &*(x.as_ptr() as *const _), //without ref
Some(ref x) => x.as_ptr(), // with ref
None => panic!("hello?")
}
}
}