2016-12-13 12 views
6

जैसा कि मैं इसे समझता हूं, [[T; 4]; 3] और [T; 12] मेमोरी में एक ही लेआउट है। इन प्रकारों के बीच मूल्य को बदलने का सबसे अच्छा तरीका क्या है? क्या मैं एक संदर्भ को दूसरे के संदर्भ में परिवर्तित कर सकता हूं? क्या मैं सभी तत्वों की प्रतिलिपि बनाने से बच सकता हूं? क्या मुझे unsafe चाहिए?एक [[टी; 4]; 3] एक [टी; 12]?

उत्तर

9

हां, आप एक संदर्भ को [[T; 4]; 3] पर [T; 12] के संदर्भ में परिवर्तित कर सकते हैं, लेकिन केवल mem::transmute का उपयोग करके असुरक्षित कोड के साथ। इसे फ़ंक्शन में लपेटना सबसे अच्छा है ताकि परिणामी संदर्भ उचित जीवनकाल असाइन किया जा सके, अन्यथा transmute संदर्भ के मुकाबले बड़े जीवनकाल के साथ संदर्भ प्राप्त करना संभव कर देगा।

fn convert<'a>(a: &'a [[u8; 4]; 3]) -> &'a [u8; 12] { 
    unsafe { std::mem::transmute(a) } 
} 

यह जीवन इलिजन नियमों के लिए धन्यवाद छोटा किया जा सकता:

fn convert(a: &[[u8; 4]; 3]) -> &[u8; 12] { 
    unsafe { std::mem::transmute(a) } 
} 

हालांकि जब असुरक्षित कोड के साथ काम कर, मैं समझता हूँ चाहते हैं आप अधिक स्पष्ट संस्करण को प्राथमिकता दी है, तो!

+1

बस स्पष्ट करने के लिए: यह थोड़ा-सा-प्रति प्रतिलिपि करता है यदि _ संदर्भ संदर्भ_ और सरणी की सामग्री नहीं है? मुझे यकीन नहीं था। –

+3

@ सिमॉन: यदि आप सरणी में _reference_ को ट्रांसमिट करते हैं, तो केवल संदर्भ की प्रतिलिपि बनाई जाती है। यदि आप _array_ को सीधे ट्रांसमिट करते हैं (जैसा कि आपने अपने उत्तर में किया था), तो संपूर्ण सरणी की प्रतिलिपि बनाई गई है। हालांकि, संकलक मूल्य के साथ क्या करता है और आप कोड को कैसे संकलित करते हैं (डीबग या रिलीज़) के आधार पर कॉपी को बढ़ा सकते हैं। –

+0

ग्रेट कोई समस्या नहीं है। मैं भविष्य में अपने लिए संदर्भ के बिंदु के रूप में वैसे भी अपना जवाब छोड़ दूंगा। स्पष्टीकरण देने के लिए धन्यवाद :) –

3

अस्वीकरण: मैं अभी तक जंग के निम्न स्तर के पक्ष के साथ वास्तव में महान नहीं हूं, मुझे नहीं पता कि निम्न स्तर के जंग में "अच्छा अभ्यास" क्या माना जाता है। यहां दी गई सलाह अच्छी विचार नहीं हो सकती है। मैं उन्हें यहाँ डाल रहा हूं क्योंकि ... अच्छा, वे काम करते हैं।

You could transmute them। समस्या यह है कि यह एक प्रतिलिपि होगी, दस्तावेज कहता है कि यह memcpy कॉल के बराबर है। यह तुम क्या चाहते थे नहीं है, लेकिन यहाँ यह वैसे भी है:

fn main() { 
    let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]; 
    let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 

    println!("a: {:?}", a); 
    println!("b: {:?}", b); 

    let c = unsafe { std::mem::transmute::<[[u8; 4]; 3], [u8; 12]>(a) }; 

    println!("c: {:?}", c); 
} 

आपका दूसरा विकल्प is to work with a raw pointer:

fn main() { 
    let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]; 
    let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 

    println!("a: {:?}", a); 
    println!("b: {:?}", b); 

    let c = &a as *const _ as *const [u8; 12]; 
    // Or it can be this: let c = &mut a as *mut [[u8; 4]; 3]; 

    for i in 0..12 { 
     let p = c as *const u8; 
     let v = unsafe { *p.offset(i) }; 
     println!("{}", v); 
    } 
} 

जो या तो विशेष रूप से महान नहीं है।

सूचक भी एक सूचक या एक ही प्रकार (के बाद से &mut T*mut T लिए डाली जा सकता है) के लिए अस्थायी सूचक हो सकता है और इसके बाद के संस्करण कोड ठीक उसी काम करता है (a साथ परिवर्तनशील चिह्नित):

let c = &mut a as *mut [[u8; 4]; 3]; 

मुझे आश्चर्य है कि यह एक एक्सवाई-समस्या का थोड़ा सा है या नहीं। हो सकता है कि जिस तरह से आप अपने डेटा के साथ काम कर रहे हैं उसे बदलने की आवश्यकता के लिए बदला जा सकता है?

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