2015-06-19 12 views
6

मेरे पास जंग में जेनिक्स के बारे में एक नया सवाल है (संस्करण 1.0)।एक सामान्य प्रकार कास्टिंग

मान लें कि मैं विभाजन करने के लिए एक सामान्य कार्य लिखता हूं। ऐसे फ़ंक्शन की उपयोगिता को कभी भी ध्यान न दें; यह सवाल सरल रखने के लिए यह एक आसान काम है।

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

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

यह प्रोग्राम संकलित करने में विफल रहता है।

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 
        ^~~~~ 

मैं समझता हूँ कि संकलक त्रुटि कह रहा है कि विभाजन आपरेशन के परिणाम टाइप Output, नहीं T है, और मैं standard library documentation में Output प्रकार देखते हैं।

मैं Output से T से कैसे परिवर्तित करूं? मैं कास्ट करने के लिए as का उपयोग करने का प्रयास करता हूं।

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

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

यह एक अलग संकलक त्रुटि का कारण बनता है।

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 
        ^~~~~~~~~~~~ 

मैं विचारों यह काम करने के लिए से बाहर हूँ, और मुझे लगता है मैं यहाँ कुछ भाषा के बारे में बुनियादी की समझ की कमी है, लेकिन मैं भी इस काम करने के लिए देखने के लिए क्या पता नहीं है। मदद? तुम क्यों समारोह

अंदर डाली नहीं कर सकते जब आप में हैं के बारे में अधिक विवरण जोड़ने के लिए

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

संपादित करें:

+1

शायद http://stackoverflow.com/q/29184358/155423 का डुप्लिकेट। – Shepmaster

उत्तर

9

आप बस समारोह की वापसी प्रकार के रूप में T::Output निर्दिष्ट करना आपका सामान्य फ़ंक्शन विभाजित करता है, संकलक अभी तक नहीं जानता है कि आप T से T::Output पर जा सकते हैं, इसलिए कलाकार अमान्य है। वे सामान्य प्रकार हैं, वे कुछ भी हो सकते हैं, कैसे संकलक जानता है कि आप T से T::Output पर जा सकते हैं?

a/bT::Output के प्रकार का उत्पादन करता है, इसलिए ऊपर दिए गए समाधान में कास्ट नहीं किया गया है, T::Output बस सही प्रकार है। सबसे अधिक (मुझे लगता है कि) सामान्य कार्यान्वयन है जब आप जानते हैं कि टी के लिए T::Output से डाली संभव है एक और संभव समाधान एसटीडी का उपयोग कर जोड़ने के लिए

संपादित :: परिवर्तित :: से

T::Output के लिए From लागू करने के लिए आप T बाध्य कर सकते हैं। यह एक पूर्ण उदाहरण है:

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

यह काम करता है, लेकिन _why_ यह काम करता है? यदि मैं 'u32' प्रकार के' टी' के साथ 'divide' को कॉल करता हूं और लौटा हुआ मान' u32' (यानी, 'चलो x: u32 = divide (42u32, 18u32);') के चर के लिए आवंटित करता हूं, तो यह संकलित करता है। 'Divide -> T' के भीतर वापसी अभिव्यक्ति क्यों' टी :: आउटपुट' से 'टी' में परिवर्तित नहीं हो सकती है, लेकिन 'divide' के बाहर लौटाए गए मान का उपयोग करते समय टाइप सिस्टम रूपांतरण की अनुमति देता है (' u32 :: आउटपुट से 'से' u32')? यानी, 'divide' के रिटर्न प्रकार के लिए 'आउटपुट'' को जोड़ना, _inside_ फ़ंक्शन से रूपांतरण को _outside_ में परिवर्तित करता है। यहाँ क्या चल रहा है? –

+2

क्योंकि जब आप अपने जेनेरिक फ़ंक्शन 'divide' में होते हैं, तो संकलक अभी तक नहीं जानता है कि आप' टी 'को' टी: आउटपुट 'पर डाल सकते हैं। (वे सामान्य हैं, वे कुछ भी हो सकते हैं, यहां तक ​​कि कुछ भी नहीं डाला जा सकता है) 'ए/बी' कुछ प्रकार के टी टी आउटपुट का उत्पादन करता है, इसलिए ऊपर दिए गए समाधान में कलाकार नहीं है, 'टी :: आउटपुट' बस है सही प्रकार – eulerdisk

4

एंड्रियास 'जवाब बताता है कि क्यों डाली असंभव है, और है कि जेनेरिक इस मुद्दे संभव हल के रूप में के रूप में कार्य कर रही है।

हालांकि, यह एकमात्र समाधान नहीं है। जंग एक सामान्य कार्य के संबंधित प्रकारों (Output यहां) को बाधित करने की क्षमता का भी समर्थन करता है।

एक वैकल्पिक होगा:

use std::ops::Div; 

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

<Output = T> बिट संकलक केवल स्वीकार करने के लिए इस प्रकार के TDiv के कार्यान्वयन एक OutputT के बराबर है, जिसके लिए काम करता है में निर्देश देता है। यह स्पष्ट रूप से अधिक प्रतिबंधित है, लेकिन यह सुनिश्चित करने की अनुमति देता है कि divide का परिणाम T है।

+2

'=' बाधा पर अच्छा बिंदु। मुझे आधिकारिक दस्तावेज़ों में बहुत कुछ नहीं मिला है, क्या आप हमें कुछ संदर्भ दे सकते हैं ?? हालांकि, और भी सामान जोड़ने के लिए, ऐसा मामला है जब आपको 'टी' के लिए 'से' विशेषता लागू करने की आवश्यकता हो सकती है। (मैंने फिर से अपनी प्रतिक्रिया संपादित की) – eulerdisk

+1

@AndreaP: यह [एसोसिएटेड प्रकार] के बहुत अंत में बताया गया है (https://doc.rust-lang.org/book/associated-types.html#trait-objects-with -साधिकृत प्रकार) अध्याय। उनके बारे में कुछ कहना नहीं है, इसलिए दस्तावेज़ बहुत कुछ नहीं कहते हैं, लेकिन मैं मानता हूं कि इसे याद करना आसान है। –

संबंधित मुद्दे