将 impl 与通用参数混合使用和不使用它们有什么影响吗?
Does mixing impl with generic parameters and without them have any implications?
说,我有以下代码:
use std::ptr::NonNull;
use std::marker::PhantomPinned;
use std::pin::Pin;
#[derive(Debug)]
struct Unmovable {
data: Vec<String>,
cache: Option<NonNull<String>>,
_pin: PhantomPinned,
}
impl<'a> Unmovable {
pub fn new(data: Vec<String>) -> Pin<Box<Self>> {
let internal = Self {
data,
cache: None,
_pin: PhantomPinned
};
let mut boxed = Box::pin(internal);
let cache = if boxed.data.len() > 0 {
Some(NonNull::from(&boxed.data[0]))
} else {
None
};
unsafe {
let ref_mut: Pin<&mut Unmovable> = Pin::as_mut(&mut boxed);
Pin::get_unchecked_mut(ref_mut).cache = cache;
}
boxed
}
pub fn get_cache(&'a self) -> Option<&'a String> {
Some(unsafe { self.cache?.as_ref() })
}
}
fn main() {
let unm = Unmovable::new(vec!["hello".to_owned(), "there".to_owned()]);
println!("{:?}", unm);
println!("{:?}", unm.get_cache());
}
我想知道,函数 new
是在泛型指定的 impl
块中实现还是在没有该泛型参数的情况下单独实现,有什么区别,因为它没有在那里使用。说实话,我有点惊讶 Rust 确实允许这样做,impl 一个不使用所有泛型的函数,因为它被禁止用于结构,例如。所以我很好奇这样的混合声明是否有一些含义。
new
函数是否相当于 impl
旁边没有泛型的单独实现?
类型参数或常量泛型将被禁止。但是 impl 上的免费生命周期是允许的。它们仅在关联类型中使用时才被禁止。原理解释in the source code:
// (*) This is a horrible concession to reality. I think it'd be
// better to just ban unconstrained lifetimes outright, but in
// practice people do non-hygienic macros like:
//
// ```
// macro_rules! __impl_slice_eq1 {
// ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
// impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
// ....
// }
// }
// }
// ```
//
// In a concession to backwards compatibility, we continue to
// permit those, so long as the lifetimes aren't used in
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
我对 rustc 的内部结构知之甚少,无法确定,但我很确定它不会影响任何事情。最好不要使用它;在需要它的方法上使用生命周期,而不是在实现上。
说,我有以下代码:
use std::ptr::NonNull;
use std::marker::PhantomPinned;
use std::pin::Pin;
#[derive(Debug)]
struct Unmovable {
data: Vec<String>,
cache: Option<NonNull<String>>,
_pin: PhantomPinned,
}
impl<'a> Unmovable {
pub fn new(data: Vec<String>) -> Pin<Box<Self>> {
let internal = Self {
data,
cache: None,
_pin: PhantomPinned
};
let mut boxed = Box::pin(internal);
let cache = if boxed.data.len() > 0 {
Some(NonNull::from(&boxed.data[0]))
} else {
None
};
unsafe {
let ref_mut: Pin<&mut Unmovable> = Pin::as_mut(&mut boxed);
Pin::get_unchecked_mut(ref_mut).cache = cache;
}
boxed
}
pub fn get_cache(&'a self) -> Option<&'a String> {
Some(unsafe { self.cache?.as_ref() })
}
}
fn main() {
let unm = Unmovable::new(vec!["hello".to_owned(), "there".to_owned()]);
println!("{:?}", unm);
println!("{:?}", unm.get_cache());
}
我想知道,函数 new
是在泛型指定的 impl
块中实现还是在没有该泛型参数的情况下单独实现,有什么区别,因为它没有在那里使用。说实话,我有点惊讶 Rust 确实允许这样做,impl 一个不使用所有泛型的函数,因为它被禁止用于结构,例如。所以我很好奇这样的混合声明是否有一些含义。
new
函数是否相当于 impl
旁边没有泛型的单独实现?
类型参数或常量泛型将被禁止。但是 impl 上的免费生命周期是允许的。它们仅在关联类型中使用时才被禁止。原理解释in the source code:
// (*) This is a horrible concession to reality. I think it'd be
// better to just ban unconstrained lifetimes outright, but in
// practice people do non-hygienic macros like:
//
// ```
// macro_rules! __impl_slice_eq1 {
// ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
// impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
// ....
// }
// }
// }
// ```
//
// In a concession to backwards compatibility, we continue to
// permit those, so long as the lifetimes aren't used in
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
我对 rustc 的内部结构知之甚少,无法确定,但我很确定它不会影响任何事情。最好不要使用它;在需要它的方法上使用生命周期,而不是在实现上。