Как вернуть, когда реф и передача собственности не сработают - PullRequest
0 голосов
/ 16 июня 2019

итак, если я верну это

self.string_ref.unwrap().as_ref()

компилятор скажет

error[E0515]: cannot return value referencing temporary value
returns a value referencing data owned by the current function

если я верну это

*self.string_ref.unwrap().as_ref()

компилятор скажет

error[E0507]: cannot move out of borrowed content

это просто сводило меня с ума

вот код: ( детская площадка )

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)
}

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Так что я в основном разобрался, что происходит, благодаря @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?")
        }
    }
}
0 голосов
/ 16 июня 2019

Разобрав ваш пример до минимума:

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`!")
        }
    }
}
as_ref возвращает &T, поэтому вы не можете вернуть принадлежащую строку, вместо этого вам нужно либо клонировать ее и затем вернуть принадлежащую строку, либо взять ссылкук нему:
//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 с помощью String::from, но нигде не храните его значение и вместо этого сразу же приводите его в указатель.Это освободит String в конце строки, что приведет к UB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...