據我了解, rust 是一種“具有”而不是“是”語言(組合優于繼承)。這使得 Liskov 替換稍微復雜一些,但使用 Traits 并非不可能。雖然我可以使用 LSP,但它似乎不是在 rust 中實作型別強制的慣用方式。我對如何操作感到困惑。
最小的例子
假設我有兩個結構
struct Real(i32);
struct Complex(Real, Real);
還有一個函式project,它接受Complex并回傳輸入的投影。
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
// we pass by reference because we need to be blazingly fast
fn project(c : &Complex) -> Complex {
Complex(c.0, Real(0))
}
fn main() {
let a = Complex(Real(1), Real(2));
let x = project(&a);
println!("{} {}i", x.0.0, x.1.0)
}
為簡單起見,請假設我們是從通過參考傳遞 Real 中受益的情況,project不應將其復制為Realand的特征的多個實作Complex。假設我們希望不時使用projecton s。Real
制作project有點通用
我的 OOP 直覺促使我為Realand制作一些超型別Complex,假設是 traitAsReal
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
trait AsReal {
fn as_real(&self) -> Real;
}
impl AsReal for Real { fn as_real(&self) -> Real { *self } }
impl AsReal for Complex { fn as_real(&self) -> Real { self.0 } }
fn project (r : &impl AsReal) -> Complex {
Complex( r.as_real(), Real(0) )
}
fn main() {
let a = Real(1);
let b = Complex(Real(2), Real(3));
let x = project(&a);
let y = project(&b);
println!("{} {}i", x.0.0, x.1.0);
println!("{} {}i", y.0.0, y.1.0);
}
但顯然,生銹的方法是AsRef<Real>使用
#[derive(Clone, Copy)]
struct Real(i32);
struct Complex(Real, Real);
fn project<U: AsRef <Real>>(r : U) -> Complex {
Complex ( *r.as_ref(), Real(0) )
}
impl AsRef<Real> for Complex {
fn as_ref(&self) -> &Real { &self.0 }
}
impl AsRef<Real> for Real {
fn as_ref(&self) -> &Real { self }
}
fn main() {
let a = Real(1);
let b = Complex(Real(2), Real(3));
let x = project(&a);
let y = project(&b);
println!("{} {}i", x.0.0, x.1.0);
println!("{} {}i", y.0.0, y.1.0);
}
這讓我不滿意:原型project變得非常冗長且難以閱讀。如此之多,以至于感覺專案使用的便利性根本不值得。
此外,這意味著該功能必須選擇將 Complex 轉換為 Real coercion,我不喜歡這個概念,因為它感覺它促使我一直在防御性地發展和使用AsRef<...>。
我覺得我沒有全貌,在這種情況下與 rust 互動的慣用方式是什么?
uj5u.com熱心網友回復:
根據您的描述,您似乎可以這樣做:
project需要一個RealComplex提供了一個into_real()方法,該方法回傳一個Real
小旁注:如果您的型別很小并且Copy,指標并不總是更快。編譯器資源管理器可以成為向您展示片段的程式集是什么的好工具/
話雖如此,我會這樣寫。
fn project(real: Real) -> Real {
// very complex logic
}
// deriving Copy makes these types behave more like numbers
#[derive(Copy, Clone)]
struct Real(i32);
#[derive(Copy, Clone)]
struct Complex(Real, Real);
impl Complex {
fn into_real(self) -> Real {
self.0
}
}
fn main() {
let real = Real(0);
let complex = Complex(Real(0), Real(0));
project(real);
project(complex.into_real());
}
如果您真的討厭撰寫into_real(),您可以通過以下方式使呼叫站點更簡單并使宣告站點更復雜:
- 實作
From<Complex>for (盡管可以說這需要它自己的特性,因為從 aReal獲取 a 的方法不止一種)RealComplex - 接受
project一個impl Into<Real>
impl From<Complex> for Real {
fn from(c: Complex) {
c.0
}
}
fn project(real: impl Into<Real>) {
let real = real.into();
// real is a `Real` here
}
雖然老實說,我只是選擇第一個選項。您的函式實際上并不需要是通用的,這會增加單態化成本。它不是非常 OOP,但 Rust 不是一種 OOP 語言。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/530635.html
標籤:哎呀仿制药锈
