Вы можете достичь чего-то подобного, не используя специализацию, но используя две разные черты и автоматическую черту, чтобы различать их.
#![feature(optin_builtin_traits)]
auto trait IsWrap {}
#[derive(Debug)]
struct Wrapper<T>(T);
impl<T> !IsWrap for Wrapper<T> {}
trait ToWrapper: Sized {
fn to_wrap(self) -> Wrapper<Self>;
}
impl<T: IsWrap> ToWrapper for T {
fn to_wrap(self) -> Wrapper<T> {
Wrapper(self)
}
}
trait ToWrapperSelf {
fn to_wrap(self) -> Self;
}
impl<T> ToWrapperSelf for Wrapper<T> {
fn to_wrap(self) -> Self {
self
}
}
fn main() {
let a = 1.to_wrap();
println!("{:?}", a);
let a = 1.to_wrap().to_wrap();
println!("{:?}", a);
}
Как и в случае предложения Чабапока , вы не можете использовать эту технику для написания универсальной функции, которая ведет себя так, когда задан один тип, и другим способом - с другим типом (хотя см. Ссылки ниже). Но вы можете использовать его, когда конкретный тип известен компилятору, но не программисту - в качестве возможного варианта использования приходят на ум макросы.
Он имеет еще одно преимущество в том, что нет никакой двусмысленности, из-за которой метод to_wrap
будет вызываться для любого типа. Каждый тип имеет не более одного to_wrap
метода, так как Wrapper
s имеет только ToWrapperSelf::is_wrap
, а не Wrapper
s имеет ToWrapper::is_wrap
.
Еще одно преимущество dis заключается в том, что !IsWrap
для Wrapper<T>
является "заразным": любой тип, который содержит или может содержать Wrapper<T>
, будет также автоматически !IsWrap
. Если вы вызовете .to_wrap()
для такого типа, компилятор не сможет найти метод и выдаст ошибку. Если это проблема, вы можете вручную реализовать IsWrap
для этих типов, но может быть более разумно искать другое, менее хрупкое решение.
(Единственное исключение из вышеперечисленного - Box<Wrapper<T>>
: вы можете позвонить ToWrapperSelf::to_wrap
, чтобы получить Wrapper<T>
. Это происходит из-за правил автоопределения и потому, что Box
является специальным .)
Смотри также