2015-06-19 16 views
6

Rust'ta (sürüm 1.0) jeneriklerle ilgili yeni bir sorum var.Genel bir türe dökme

Bölünme yapmak için genel bir işlev yazdığımı varsayalım. Böyle bir işlevin yararlılığını boş vermeyin; Bu soruyu basit tutmak için basit bir işlev.

fn divide<T: std::ops::Div>(a: T, b: T) -> T { 
    a/b 
} 

fn main() { 
    println!("{}", divide(42, 18)) 
} 

Bu program derlenemiyor.

src/main.rs:2:5: 2:10 error: mismatched types: 
expected `T`, 
    found `<T as core::ops::Div>::Output` 
(expected type parameter, 
    found associated type) [E0308] 
src/main.rs:2  a/b 
        ^~~~~ 

Ben derleyici hata Bölme işleminin sonucu Output değil T tip olduğunu bana söylediğini anlıyorum ve standard library documentation içinde Output türünü görmek.

Output - T nasıl dönüştürülür? Yayınlamak için as kullanmayı denerim.

fn divide<T: std::ops::Div>(a: T, b: T) -> T { 
    (a/b) as T 
} 

fn main() { 
    println!("{}", divide(42, 18)) 
} 

Bu, farklı bir derleyici hatasına neden olur.

src/main.rs:2:5: 2:17 error: non-scalar cast: `<T as core::ops::Div>::Output` as `T` 
src/main.rs:2  (a/b) as T 
        ^~~~~~~~~~~~ 

Ben bu işi yapmak için fikir gelmiyor ve ben burada dil hakkında temel bir şeyin anlayış eksikliği farkındayım ama ben bile bu işi yapmak için aramaya bilmiyorum. Yardım et? Eğer İÇİNDE olduğunuz zaman fonksiyonu

iç döküm yapamaz nedeniyle ilgili daha fazla açıklama eklemek için

fn divide<T: std::ops::Div>(a: T, b: T) -> T::Output { 
    a/b 
} 

Düzenleme:

+1

Muhtemelen bir http://stackoverflow.com/q/29184358/155423 kopyası. – Shepmaster

cevap

9

Sadece dönüş işlevinin türü olarak T::Output belirtmek zorunda jenerik işleviniz bölünür, ancak derleyici T'u T::Output'a atayabileceğinizi bilmez, bu nedenle yayın geçersizdir. Bunlar jenerik tipler, herhangi bir şey olabilirler, derleyici T'dan T::Output'a nasıl yayınlayabileceğinizi biliyor?

a/bT::Output türünde bir şey üretir, bu nedenle yukarıdaki çözümde yok, T::Output sadece doğru türdür.

Düzenleme std başka bir olası çözüm eklemek için :: dönüştürmek ::

itibaren en (Sanırım) ile T T::Output gelen dökme mümkün olduğunu bildiğinizde jenerik uygulamasıdır. T::Output için From uygulamak için T bağlayabilirsiniz. Bu tam bir örnektir:

use std::ops::Div; 
use std::convert::From; 

fn divide<T: Div>(a: T, b: T) -> T 
    where T: From<<T as Div>::Output> 
{ 
    T::from(a/b) 
} 

#[derive(Debug)] 
struct Bip(u32); 

impl Div for Bip { 
    type Output = f32; 

    fn div(self, rhs: Bip) -> f32 { 
     (self.0/rhs.0) as f32 
    } 
} 

impl From<f32> for Bip { 
    fn from(value: f32) -> Self { 
     Bip(value as u32) 
    } 
} 

fn main() { 
    println!("{:?}", divide(12, 4)); 
    println!("{:?}", divide(Bip(12), Bip(4))); 
} 
+0

Bu işe yarıyor, ama _why_ işe yarıyor mu? 'U32' türünde 't' ile 'divide' ve 'u32' türünde bir değişkene dönüş değeri atarsam (yani x: u32 = böl (42u32, 18u32); ') sonra derler. Neden 'di '-' T 'dönüş ifadesi' T :: Output'dan 'T''ye dönüşemez,' 'divide''nın dışında döndürülmüş değer kullanılırsa, type sistemi dönüşüme izin verir. 'u32' ye? Yani, 'bölme' dönüş türüne 'bölme' ekleme işlemi, dönüştürmeyi _inside_ işlevinden işleve _outside_ dizinine taşır. Burada neler oluyor? –

+2

Genel işleviniz "divide" ise, derleyici henüz "T" yi "T: Output" a çevirebileceğinizi bilmiyor. (Bunlar jeneriktir, her şey olabilir, hatta bir şey yapamazlar) 'a/b'' T :: Output' türünde bir şey üretir, bu yüzden yukarıdaki çözümde döküm yoktur, 'T :: Output' basitçe Doğru tip – eulerdisk

4

Andreas'ın cevabı dökme imkansız açıklıyor ve bu jenerik mümkün çözer bu sorunu olarak işlev yapma.

Ancak, tek çözüm değildir. Pas ayrıca, genel bir işlevin ilişkili türleri (Output burada) sınırlama yeteneğini de destekler.

alternatif olacaktır:

use std::ops::Div; 

fn divide<T>(a: T, b: T) -> T 
    where T: Div<Output = T> 
{ 
    a/b 
} 

<Output = T> bitlik bu Div uygulanması T eşit bir Output sahip olduğu türlerini T fonksiyonları sadece kabul için derleyici bildirir. Bu açıkça daha kısıtlayıcıdır, ancak divide sonucunun T türünde olmasını sağlar.

+2

'=' kısıtlaması hakkında iyi bir nokta. Resmi belgelerinde çok fazla bulamadım, bize biraz referans verebilir misiniz? Ancak daha da fazla şey eklemek için, '' '' '' '' '' ''' için uygulanacak '' özelliğinin gerektirebileceği durumlar söz konusudur. (Yanıtımı tekrar düzenledim) – eulerdisk

+1

@AndreaP: [Associated Types] (https://doc.rust-lang.org/book/associated-types.html#trait-objects-with) 'in sonuna gelindik. ilişkili tipler) bölüm. Onlar hakkında söylenecek çok şey yok, bu yüzden dokümanlar fazla konuşmuyor, ama itiraf etmenin kolay olduğunu itiraf ediyorum. –

İlgili konular