簡體   English   中英

有沒有辦法創建基於特征實現的結構?

[英]Is there a way to create a struct based on a trait implementation?

我正在嘗試使用具有一種方法的多種實現的結構:

trait Trait { fn apply(&self) -> vec<usize>; }

struct Bar<X> { vec: Vec<usize> }

impl<X> Bar<X> {
    pub fn new(vec: Vec<usize>) -> Self { Self{vec} }
    pub fn test(&self) {
        // Things here
        println!("Method: {:?}", self.apply()); 
        // Things there
    }
}

impl Trait for Bar<ThisWay> {
    fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x.pow(2)).collect() }
}

impl Trait for Bar<ThatWay> {
    fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x + 2).collect() }
}

fn main() {
   Bar<ThisWay>::new(vec![1,2,3]).test();
   Bar<ThatWay>::new(vec![1,2,3]).test();
}

哪個會返回:

>>> [1,4,9];
>>> [3,4,5];

我知道我可以創建 2 個結構體以不同的方式實現這些方法,但這感覺不對,因為它可能有很多冗余代碼。 我也知道我可以參考該實現方法:

trait Trait { fn apply(vec: &Vec<usize>) -> Vec<usize>; }

impl Struct{
    // fn new
    test(&self, t: &impl Trait) {
    // Things here
    println!("{:?}", t::apply(&self.vec));
    // Things there
    }
}
struct ThisWay;
struct ThatWay;
impl Trait for ThisWay {fn apply(vec: &Vec<usize>) -> Vec<usize> {///} };
impl Trait for ThatWay {fn apply(vec: &Vec<usize>) -> Vec<usize> {///} };
fn main() {
     let this_way = ThisWay{}; 
     let that_way = ThatWay{};
     let problem = Bar::new(vec![1,2,3]);
     problem.test(&this_way);
     problem.test(&that_way);
}

當我想在給定的結構中使用許多參數時,這種方法似乎不必要地復雜:

fn hill_climber(&self, nullary_op: &impl NullaryOperator, unary_op: &impl UnaryOperator, ...) {
   self.vec = nullary_op();
   self.vec = unary_op(&self.vec, self.n, self.m, self.jobs, self.stuff, ...);
}

這似乎是一種被詛咒的編寫代碼的方式。 當方法實現不使用參數(例如m )而其他人使用該參數時會發生什么?

特征用於定義共享行為。 在您的示例中,您希望以不同的方式實現相同的特征。 這違背了 trait 的目的。 你應該有兩個特征,而不是像你嘗試的那樣有兩個結構:

trait ThisWay {
    fn apply(&self) -> Vec<usize>;
}

trait ThatWay {
    fn apply(&self) -> Vec<usize>;
}

現在你可以為你的結構實現這兩個特征:

struct Bar {
    vec: Vec<usize>,
}

impl ThisWay for Bar {
    fn apply(&self) -> Vec<usize> {
        self.vec.iter().map(|x| x.pow(2)).collect()
    }
}

impl ThatWay for Bar {
    fn apply(&self) -> Vec<usize> {
        self.vec.iter().map(|x| x + 2).collect()
    }
}

因為Bar實現了ThisWayThatWay ,它現在有兩個apply方法的定義。 為了消除它們之間的歧義,我們必須使用完全限定的語法:

let this_bar = Bar::new(vec![1, 2, 3]);
println!("Method: {:?}", <Bar as ThisWay>::apply(&this_bar));
    
let that_bar = Bar::new(vec![1, 2, 3]);
println!("Method: {:?}", <Bar as ThatWay>::apply(&that_bar));

而且,正如預期的那樣,您會得到兩個不同的輸出:

Method: [1, 4, 9]
Method: [3, 4, 5]

作為另一個答案的替代方案,您還可以使用更類似於原始示例的方法,使用泛型和零大小的結構類型作為要使用的方法的“標記”。 這是一個完整的例子:

// PhantomData allows us to "use" a generic without having an actual field
use std::marker::PhantomData;

// These structs will be used to indicate which implementation we want
struct ThisWay;
struct ThatWay;

trait Trait { fn apply(&self) -> Vec<usize>; }

struct Bar<X> {
    vec: Vec<usize>,
    // This extra field is here to stop the compiler complaining about not using X
    _marker: PhantomData<X>,
}

impl<X> Bar<X> {
    pub fn new(vec: Vec<usize>) -> Self { Self { vec, _marker: PhantomData } }

    // Note the new "where" clause here - we can only implement this function if Bar<X> implements Trait
    pub fn test(&self) where Self: Trait {
        // Things here
        println!("Method: {:?}", self.apply()); 
        // Things there
    }
}

impl Trait for Bar<ThisWay> {
    fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x.pow(2)).collect() }
}

impl Trait for Bar<ThatWay> {
    fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x + 2).collect() }
}

fn main() {
   Bar::<ThisWay>::new(vec![1,2,3]).test();
   Bar::<ThatWay>::new(vec![1,2,3]).test();
}

運行這個,輸出正確地反映了正在使用的不同功能:

Method: [1, 4, 9]
Method: [3, 4, 5]

這種方法與另一個答案具有不同的語義:而另一個答案允許您構造一個能夠與這兩個函數一起使用的Bar ,這種方法將您鎖定在類型級別的一個實現中,因為Bar<ThisWay>Bar<ThatWay>是兩種不同的類型,每一種都只提供一個apply功能。 在某些情況下,這對於類型安全來說可能是可取的,但在這種特殊情況下可能不是您所需要的。

// since x is declared as `Bar<ThatWay>`, we can only ever use the `ThatWay` implementation of `apply`/`test`
let x: Bar<ThatWay> = Bar::new(vec![1, 2, 3]);
x.test(); // -> Method: [3, 4, 5]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM