2015-07-05 7 views
5

टीएल; डीआर मैं सामान्य अंतर्निहित डेटा को संदर्भित करने वाले सामान्य प्रकारों पर डेटा संरचना कैसे बना सकता हूं?जेनेरिक प्रकार, स्वामित्व, और लगातार डेटा संरचनाएं

यह प्रश्न जंग में दोनों अर्थशास्त्र और अच्छे डेटा मॉडलिंग के बारे में है। नीचे दिया गया कोड मेरे वास्तविक प्रश्न को हाइलाइट करने के लिए मेरी समस्या का एक (अधिक) छोटा आसवन है, न कि मेरा वास्तविक कोड।

लक्ष्य एक ऐसा फ़ंक्शन बनाना है जो कई वैक्टर बनाता है जिसमें सामान्य प्रकार के साझा डेटा के संदर्भ शामिल हैं। निम्नलिखित उदाहरण के नामकरण में मैं वेक्टरों का संग्रह वापस करने में सक्षम होना चाहता हूं जो Struct1 और Struct2 (विशेषता Trait द्वारा समेकित) को संग्रहीत कर सकते हैं, हालांकि (मेरे वास्तविक कोड में) Struct1 और Struct2 अपेक्षाकृत अपेक्षाकृत हैं बड़े और अपेक्षाकृत कई जगहों पर अपेक्षाकृत बार संग्रहीत किया जाएगा, मैं साझा डेटा के संदर्भों को संग्रहीत करना चाहता हूं, उन्हें जगह पर कॉपी न करें।

वर्तमान समस्या का सामना करना पड़ रहा हूँ (और वहाँ कई मध्यवर्ती संशोधन किया गया है) है कि:

  1. के बाद से डेटा के प्रकार मैं दुकान कोशिश कर रहा हूँ Trait, जो Sized मैं नहीं कर रहे हैं मेरी वैक्टर
  2. में संदर्भ स्टोर करने के लिए के बाद से प्रत्येक struct कई वैक्टर से संदर्भित किया जाएगा की जरूरत है, एक & संदर्भ आवश्यक
  3. दार्शनिक है, कोई विलक्षण एक दिया struct के "मालिक" कोई "सही" जगह रहना नहीं है, इसलिए मेरे structs तो वेके साथ गुंजाइश से बाहर नहीं जाते हैंसमारोह।
    1. मैंने Traits के वैश्विक वेक्टर के माध्यम से इसे हल करने का प्रयास किया, जिसमें मैं संदर्भों को इंगित कर सकता हूं, दुर्भाग्यवश समस्या (1) उपरोक्त उस रणनीति को रोकने के लिए प्रतीत होती है।

struct Struct1; 
struct Struct2; 

trait Trait { fn name(&self) -> &str; } 
impl Trait for Struct1 { fn name(&self) -> &str { "Struct1" } } 
impl Trait for Struct2 { fn name(&self) -> &str { "Struct2" } } 

fn shallow_copy<'a>(v: &'a Vec<&'a Box<Trait>>) -> Vec<&'a Box<Trait>> { 
    v.iter().map(|x|*x).collect() 
} 

fn build_vectors<'a>() -> (Vec<&'a Box<Trait>>, Vec<&'a Box<Trait>>) { 
    let box_struct1: &Box<Trait> = &(Box::new(Struct1) as Box<Trait>); 
    let box_struct2: &Box<Trait> = &(Box::new(Struct2) as Box<Trait>); 

    let vec1: Vec<&Box<Trait>> = vec![box_struct1]; 
    let mut vec2: Vec<&Box<Trait>> = shallow_copy(&vec1); 

    vec2.push(box_struct2); 

    (vec1, vec2) 
} 

fn join_names(v: &Vec<&Box<Trait>>) -> String { 
    v.iter().map(|s| s.name()).collect::<Vec<_>>().connect(" ") 
} 

fn main() { 
    let (vec1, vec2) = build_vectors(); 

    println!("vec1: {}", join_names(&vec1)); 
    println!("vec2: {}", join_names(&vec2)); 
} 

वांछित आउटपुट है:

vec1: Struct1 
vec2: Struct1 Struct2 

उत्तर

6

यह Rc के लिए एक आदर्श उपयोग के मामले की तरह लगता है। Rc एक संदर्भ-गणना प्रकार है जो आपको एक ही मान पर एकाधिक मालिक होने की अनुमति देता है।

use std::rc::Rc; 

struct Struct1; 
struct Struct2; 

trait Trait { fn name(&self) -> &str; } 
impl Trait for Struct1 { fn name(&self) -> &str { "Struct1" } } 
impl Trait for Struct2 { fn name(&self) -> &str { "Struct2" } } 

fn shallow_copy<'a>(v: &[Rc<Trait + 'a>]) -> Vec<Rc<Trait + 'a>> { 
    v.iter().map(|x| x.clone()).collect() 
} 

fn build_vectors() -> (Vec<Rc<Trait>>, Vec<Rc<Trait>>) { 
    let vec1: Vec<Rc<Trait>> = vec![Rc::new(Struct1)]; 
    let mut vec2: Vec<Rc<Trait>> = shallow_copy(&vec1); 

    vec2.push(Rc::new(Struct2)); 

    (vec1, vec2) 
} 

fn join_names<'a>(v: &[Rc<Trait + 'a>]) -> String { 
    v.iter().map(|s| s.name()).collect::<Vec<_>>().connect(" ") 
} 

fn main() { 
    let (vec1, vec2) = build_vectors(); 

    println!("vec1: {}", join_names(&vec1)); 
    println!("vec2: {}", join_names(&vec2)); 
} 

ध्यान दें कि shallow_copy में बंद clone() का उपयोग करता Rc क्लोन करने के लिए। Rc क्लोनिंग एक नया Rc बनाता है जो एक ही मान को इंगित करता है (अंतर्निहित मान क्लोन नहीं है), और साझा संदर्भ संख्या 1 से बढ़ी है। Rc को छोड़कर संदर्भ गणना में कमी आती है, और जब संदर्भ गणना शून्य पर गिर जाती है , अंतर्निहित मूल्य गिरा दिया गया है।

वैसे, मैंने Vec संदर्भों के बजाय स्लाइस संदर्भ लेने के लिए कुछ फ़ंक्शंस बदल दिए हैं, क्योंकि यह फ़ंक्शंस को अधिक सामान्य बनाता है (उदाहरण के लिए आप सरणी से भी स्लाइस प्राप्त कर सकते हैं)।

इसके अलावा, मैं विशेषता, एक जीवन भर के साथ वस्तुओं क्योंकि एक एनोटेशन के बिना, संकलक 'static (यानी Trait + 'static) मान लिया गया है, "जिसका अर्थ है Trait के एक कार्यान्वयन है कि किसी भी उधार संकेत (जो की तुलना में कम कर रहे हैं शामिल नहीं है टिप्पणी करने के लिए किया था 'static) ", और इससे आजीवन त्रुटियां हुईं।

+0

आप जंग में मेरा विश्वास बहाल कर रहे हैं, मुझे थोड़ा डरावना हो रहा था। बहुत बढ़िया जवाब। – user12341234

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