![](/img/trans.png)
[英]how do I return a pointer to an array from a function using a struct as the interface
[英]Can I return a struct which uses PhantomData from a trait implementation to add a lifetime to a raw pointer without polluting the interface?
在這個問題中,有人評論說您可以使用PhantomData
在結構內部添加綁定到原始指針的生存期。 我以為我會嘗試在我正在研究的現有代碼上執行此操作。
這是我們(最小化)的起點。 編譯( 操場 ):
extern crate libc;
use libc::{c_void, free, malloc};
trait Trace {}
struct MyTrace {
#[allow(dead_code)]
buf: *mut c_void,
}
impl MyTrace {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
}
}
}
impl Trace for MyTrace {}
impl Drop for MyTrace {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer {
trace: Option<MyTrace>,
}
impl MyTracer {
fn new() -> Self {
Self { trace: None }
}
}
impl Tracer for MyTracer {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
我認為上述代碼的問題是, 從理論上講 ,我可以將buf
指針移出MyTrace
並在結構死亡后使用。 在這種情況下,由於Drop
實現,基礎緩沖區將被釋放。
通過使用PhantomData
我們可以確保只能獲取對buf
引用,並且這些引用的生命周期都綁定到MyTrace
實例從何處來。
我們可以這樣進行( 游樂場 ):
extern crate libc;
use libc::{c_void, free, malloc};
use std::marker::PhantomData;
trait Trace {}
struct MyTrace<'b> {
#[allow(dead_code)]
buf: *mut c_void,
_phantom: PhantomData<&'b c_void>,
}
impl<'b> MyTrace<'b> {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
_phantom: PhantomData,
}
}
}
impl<'b> Trace for MyTrace<'b> {}
impl<'b> Drop for MyTrace<'b> {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer<'b> {
trace: Option<MyTrace<'b>>,
}
impl<'b> MyTracer<'b> {
fn new() -> Self {
Self { trace: None }
}
}
impl<'b> Tracer for MyTracer<'b> {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
但這會產生錯誤:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:53:36
|
53 | Box::new(self.trace.take().unwrap())
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'b as defined on the impl at 46:1...
--> src/main.rs:46:1
|
46 | impl<'b> Tracer for MyTracer<'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::option::Option<MyTrace<'_>>
found std::option::Option<MyTrace<'b>>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<Trace + 'static>
found std::boxed::Box<Trace>
我有三個子問題:
PhantomData
的動機? 'static
來自哪里? stop
界面的情況下使其工作? 具體來說,是否沒有在返回類型中添加生存期? 我將忽略您的直接問題,因為我相信您是在誤解了幾個初始步驟之后才提出的。
從理論上講,我可以將
buf
指針移出MyTrace
並在結構死亡后使用
復制指針,不移動指針,但是可以。
通過使用
PhantomData
我們可以確保僅獲取對buf
引用
這不是真的。 即使您添加了PhantomData
仍然很容易獲得原始指針的副本並濫用它。
在這種情況下,我是否正確理解
PhantomData
的動機?
PhantomData
當您想要表現出某種類型的值而實際上卻沒有該值時,將使用PhantomData
。 當有東西要參考假裝有什么參考是唯一有用的。 在您的示例中沒有這樣的值可供參考。
Rust文檔說了一些有關原始指針和
PhantomData
,但我也許弄錯了
該示例實際上很好地說明了我的觀點。 Slice
類型旨在表現為好像引用了從中借用的Vec
:
fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T>
由於這Slice
類型實際上並沒有一個參考,它需要一個PhantomData
行動象它有一個參考。 請注意,壽命'a
不僅由整塊布組成-它還與現有值( Vec
)有關。 在Vec
移動之后,這將導致Slice
內存不安全,因此有意義的是包括Vec
的生存期。
為什么在另一個問題中的評論者建議我使用
PhantomData
來提高我的原始指針的類型安全性
您可以使用PhantomData
來提高用作引用的原始指針的安全性,但是您的引用中沒有現有的Rust值。 如果指針在引用后面具有某些值,那么您也可以使用它來確保正確性,您的指針似乎也是如此。 但是,由於它是c_void
,所以它並不是真正有用的。 您通常將其視為PhantomData<MyOwnedType>
。
錯誤消息中的
'static
來自哪里?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.