我想要一個函式有一個可選的泛型型別引數來做這樣的事情:
fn main() {
bar::<()>();
}
fn bar<F: Foo>() {
let x = some_computation();
if F != () {
let foo = F::new(x);
foo.foo();
}
}
trait Foo {
fn new(x: u64) -> Self;
fn foo(&self);
}
有沒有辦法有一個可選的型別引數?如果是這樣,有沒有辦法檢查型別引數是否存在于函式中?
我想答案是否定的,但是可以用宏來做到這一點嗎?
uj5u.com熱心網友回復:
通常,您不能為函式指定默認型別引數,并且除了通過 trait 上的方法之外,您無法區分型別引數。
對此最簡單的解決方法是只有兩個函式,例如barand bar_with,其中一個不接受型別引數,另一個接受一個型別引數:
// call with no type parameters
pub fn bar() {
let x = some_computation();
}
// call with type parameter
pub fn bar_with<F: Foo>() {
let x = some_computation();
let foo = F::new(x);
foo.foo();
}
如果函式足夠復雜,您可以擁有兩個函式都呼叫的私有輔助函式:
// call with no type parameters
pub fn bar() {
bar_inner(|_x| { /* do nothing */ })
}
// call with type parameter
pub fn bar_with<F: Foo>() {
bar_inner(|x| {
let foo = Foo::new(x);
foo.foo();
})
}
fn bar_inner<Func: FnOnce(u64)>(func: Func) {
let x = some_computation();
func(x);
}
或者,您可以使用為所有Foo型別實作的附加特征和默認型別 ( ())來解決此問題:
trait BarArg {
fn bar_inner(x: u64);
}
impl<F: Foo> BarArg for F {
fn bar_inner(x: u64) {
let foo = foo::new(x);
foo.foo();
}
}
impl BarArg for () {
fn bar_inner(_x: u64) {
// do nothing
}
}
fn bar<B: BarArg>() {
let x = some_computation();
B::bar_inner(x)
}
uj5u.com熱心網友回復:
您無法匹配型別本身,但從外觀上看,您需要根據型別不同的功能。最好的方法是impl Foo針對您希望能夠處理的任何型別。這是我對您的代碼示例的解釋:
fn main() {
let a = Bar::from(()).some_completion();
let b = Bar::from(1234).some_completion();
}
trait Foo {
fn some_completion(&self) -> Self;
}
struct Bar {}
impl From<u64> for Bar {
fn from(x: u64) -> Self {
todo!();
}
}
impl From<()> for Bar {
fn from(x: ()) -> Self {
todo!();
}
}
impl Foo for Bar {
fn some_completion(&self) -> Self {
Self { /* something different */ }
}
}
如果您確實需要泛型函式,這std::str::parse是一個很好的示例,說明如何傳入型別(在本例中為數字型別)并更改回傳型別。
uj5u.com熱心網友回復:
我現在知道了!:D 我只能提供一個 noop 實作Foo:
pub struct NoopFoo {}
impl Foo for NoopFoo {
fn new(_: u64) -> Self { NoopFoo {} }
fn foo(&self) {}
}
我仍然很好奇這是否可以用宏解決...
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/363424.html
