如何 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()
        }
    }
}

这里有一些错误:

  1. 最明显的一个是您试图取得 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`!")
        }
    }
}
  1. 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?")
        }
    }
}