2016-08-24 21 views
6

Rust kitabını online olarak okudum ve 4.1, Operators and Overloading adresine ulaştım. std::ops::Add'un, ayrı ayrı tanımlanmış bir type Output ile fn add(self, rhs: RHS) -> Self::Output; olarak tanımladığını gördüm.Neden Rust'un operatörleri Çıkış değişkenine sahipler?

Burada neler olduğunu anlıyorum: add işlevi, self sol tarafını ve RHS genel parametre türü olarak sağ tarafını kabul eder.

Çıkış türünün neden başka bir genel (ex. Add<RHS, Output>) olmak yerine Output diğer adıyla tanımlandığını bilmek istiyorum. Bu sadece bir kongre mi, yoksa belirli bir nedeni var mı?

cevap

7

İşlevler değişkenler üzerinde çalışırken, özellikleri türlerde çalışan işlevler olarak düşünebilirsiniz. Bu şekilde düşünüldüğünde, tip parametreleri işleve girdi olarak işlev görür ve ilişkili türler çıktı olarak işlev görür. Output yana

biz impl Add isteyen iki tip A ve B için ilişkili bir türüdür, biz tek Output tip toplama ile sınırlıdır. Output bir tip parametresiydi,ve B için impl Add ve çeşitli şekillerde olabilir.

trait Mul<RHS, Output> { 
    fn mul(self, rhs: RHS) -> Output; 
} 
Şimdi

bize Complex türü tanımlayalım:

#[derive(Debug, Clone, Copy)] 
struct Complex { 
    x: f64, 
    y: f64, 
} 

impl Complex { 
    fn new(x: f64, y: f64) -> Complex { 
     Complex { x: x, y: y } 
    } 
} 

Biz çarpın edebilmek istiyorum Örneğin

bize Output bir parametredir bir Mul özelliği tanımlayalım f64:

impl Mul<f64, Complex> for Complex { 
    fn mul(self, rhs: f64) -> Complex { 
     Complex::new(self.x * rhs, self.y * rhs) 
    } 
} 

Bu her şey yolunda. Ancak, ikinci bir uygulaması ile gelebilir:

impl Mul<f64, f64> for Complex { 
    fn mul(self, rhs: f64) -> f64 { 
     self.x * rhs 
    } 
} 

artık bir f64 tarafından Complex çarpın, çağrılmalıdır ve ekstra türü bilgileri arayan tarafından temin edilecek gerekli olan uygulama belirsiz. İlgili bir tür Output yaparak, bu izin verilmez.Aşağıdaki kod çelişkili uygulamaları için bir derleyici hatası atar:

impl std::ops::Mul<f64> for Complex { 
    type Output = Complex; 
    fn mul(self, rhs: f64) -> Complex { 
     Complex::new(self.x * rhs, self.y * rhs) 
    } 
} 

impl std::ops::Mul<f64> for Complex { 
    type Output = f64; 
    fn mul(self, rhs: f64) -> Complex { 
     self.x * rhs 
    } 
} 

Full example

+0

Anladım. Yani, "Mul " ile, hangisini istediğinize karar vermek için değişken türünüzü "x: Karmaşık" veya "x: f64" olarak ayarlamanız gerekir, bu nedenle "Tür Çıktısı" kararı öncelikli olarak "düzenli" bir karardı. . Bu en iyi cevaba benziyor ama anladığımdan emin olmak istiyorum; ben takip ederim – BHustus

+0

Anladığım kadarıyla, evet. – paholg

+0

Ve benzer şekilde, standart uygulamanın 'üzerine yazılmasına' yönelik herhangi bir girişim başarısızlıkla karşılanır; bu, herhangi bir "T" için tanımlanmış bir 'std :: ops :: Mul ' türüne sahip olduğunda, buna güvenilebilir * sadece * uygulama. Tamam, sanırım anladım. Teşekkürler! – BHustus

4

Çıkış türünü kimlerin belirleyeceği ile ilgili. Genellikle iki türü çarptığınızda, f64 tarafından f64 deyin, sonuç türünün ne olması gerektiği açık: f64. Arayanın, String sonuç türünü sorması mantıklı olmaz - bu yüzden bir giriş olarak anlam ifade etmiyor.

Seçimin farklı çıktılarını isteyebileceğiniz bazı durumlar hayal edebiliyorum, ama biraz niş (u32 * u32 tam u64 sonucu döndürüyor mu?); artı birden fazla seçenek varsa, hangisini istediğinizi nasıl belirlersiniz? Add<u32, u64>::add(a, b) yazarken, a*b*c gibi basit ifadeleri belirsiz yapar ve tür çıkarımını çok daha zorlaştırır!

+0

Bu soru değil. Benim soruma göre, 'Neden çıktı türü başka bir jenerik olmak yerine' Çıktı 'takma adıyla tanımlanıyor?' Çıktı türünü belirtmek isteyebileceğinizi anlıyorum - programlama için yeni değilim - ama neden bu kadar belirgin olduğunu anlamış olmak istiyorum. – BHustus

+1

'Add ' 'Output' bir giriş türü parametresi yaptı, ancak bir giriş değil: LHS (Self) ve RHS'nin bir işlevi. Daha açık olması için cevabımı yeniden çalışacağım. –

İlgili konular