يكون &[تي] حرفيا اسم مستعار لشريحة في الصدأ?
-
21-12-2019 - |
سؤال
&[T]
هو الخلط لي.
افترضت بسذاجة أن مثل &T
, &[T]
كان المؤشر, ، أي عنوان مؤشر رقمي.
ومع ذلك ، لقد رأيت بعض التعليمات البرمجية مثل هذا ، أنني فوجئت إلى حد ما لرؤية العمل بشكل جيد (مبسطة لأغراض العرض التوضيحي;ولكن ترى رمز مثل هذا في العديد من' أس شريحة () ' تطبيقات):
extern crate core;
extern crate collections;
use self::collections::str::raw::from_utf8;
use self::core::raw::Slice;
use std::mem::transmute;
fn main() {
let val = "Hello World";
{
let value:&str;
{
let bytes = val.as_bytes();
let mut slice = Slice { data: &bytes[0] as *const u8, len: bytes.len() };
unsafe {
let array:&[u8] = transmute(slice);
value = from_utf8(array);
}
// slice.len = 0;
}
println!("{}", value);
}
}
لذا.
اعتقدت في البداية أن هذا رمز غير صالح.
وهذا هو ، على سبيل المثال من Slice
تم إنشاؤه داخل نطاق الكتلة يتم إرجاعه إلى خارج نطاق الكتلة (عن طريق التحويل) ، وعلى الرغم من تشغيل الكود ، فإن println!
هو في الواقع الوصول إلى البيانات التي لم تعد صالحة من خلال مؤشرات غير آمنة.سيئة!
...لكن لا يبدو أن هذا هو الحال.
النظر في التعليق على الخط // slice.len = 0;
هذا الرمز لا يزال يعمل بشكل جيد (يطبع 'مرحبا العالم') عندما يحدث هذا.
وبالتالي فإن الخط...
value = from_utf8(array);
إذا كان مؤشر غير صالح إلى متغير 'شريحة' ، فإن len
في ال println()
سيكون البيان 0 ، لكنه ليس كذلك.على نحو فعال نسخة ليس فقط من قيمة المؤشر ، ولكن نسخة كاملة من Slice
هيكل.
هل هذا صحيح?
هل هذا يعني أنه بشكل عام صالح للعودة أ &[T]
طالما أن مؤشر البيانات الداخلية الفعلي صالح ، بغض النظر عن نطاق الأصلي &[T]
يتم إرجاع ذلك ، لأن أ &[T]
الاحالة هي عملية نسخة?
(يبدو لي أن هذا أمر بديهي للغاية...لذلك ربما أنا سوء فهم;إذا أنا على حق ، وجود اثنين &[T]
هذه النقطة إلى نفس البيانات لا يمكن أن تكون صالحة ، لأنها لن مزامنة أطوال إذا قمت بتعديل واحد...)
المحلول
شريحة &[T]
, ، كما لاحظت ،هو" مكافئ " للهيكل std::raw::Slice
.في الواقع, Slice
هو تمثيل داخلي لـ &[T]
القيمة ، ونعم ، هو مؤشر وطول البيانات وراء هذا المؤشر.في بعض الأحيان يسمى هذا الهيكل "مؤشر الدهون" ، وهذا هو ، مؤشر وقطعة إضافية من المعلومات.
عندما تمر &[T]
قيمة حولها ، كنت في الواقع مجرد نسخ محتوياته-المؤشر والطول.
إذا كان مؤشر غير صالح لمتغير 'شريحة' ، فإن لين في بيان برينتلن() سيكون 0 ، لكنه ليس كذلك.على نحو فعال نسخة ليس فقط من قيمة المؤشر ، ولكن نسخة كاملة من هيكل شريحة.هل هذا صحيح?
لذا ، نعم ، بالضبط.
هل هذا يعني أنه بشكل عام صالحة للعودة &[ر] طالما أن مؤشر البيانات الداخلية الفعلي صالح, بغض النظر عن نطاق الأصلي & [ر] التي يتم إرجاعها, لأن &[ر] الاحالة هي عملية نسخة?
وهذا صحيح أيضا.هذه هي الفكرة الكاملة للمراجع المستعارة ، بما في ذلك الشرائح - يتم فحص المراجع المستعارة بشكل ثابت لاستخدامها طالما أن مرجعها على قيد الحياة.عندما يهبط التوقيت الصيفي أخيرا ، ستكون الشرائح والمراجع العادية أكثر توحيدا.
(يبدو لي أن هذا أمر بديهي للغاية...لذلك ربما أنا سوء فهم;إذا كنت على حق ، فإن وجود اثنين و[ر] يشيران إلى نفس البيانات لا يمكن أن يكون صالحا ، لأنهما لن يتزامنا الأطوال إذا قمت بتعديل واحدة...)
وهذا في الواقع مصدر قلق صحيح تماما;انها واحدة من المشاكل مع التعرج.ومع ذلك ، تم تصميم الصدأ بالضبط لمنع مثل هذه الأخطاء.هناك نوعان من الأشياء التي تجعل التعرج من شرائح صالحة.
أولا ، لا يمكن للشرائح تغيير الطول;لا توجد طرق محددة على &[T]
مما يسمح لك بتغيير طوله في مكانه.يمكنك إنشاء شريحة مشتقة من شريحة ، لكنها ستكون كائنا جديدا على الإطلاق.
ولكن حتى إذا لم تتمكن الشرائح من تغيير الطول ، إذا كان من الممكن تحور البيانات من خلالها ، فإنها لا تزال قادرة على إحداث كارثة إذا تم تسميتها.على سبيل المثال ، إذا كانت القيم في الشرائح مثيلات تعداد ، فإن تغيير قيمة في مثل هذه الشريحة المستعارة قد يجعل المؤشر إلى الأجزاء الداخلية لقيمة التعداد الموجودة في هذه الشريحة غير صالح.لذلك ، ثانيا ، شرائح الصدأ المستعارة (&[T]
) غير قابلة للتغيير.لا يمكنك تغيير القيم الواردة فيها ولا يمكنك أخذ مراجع قابلة للتغيير فيها.
هذه الميزات اثنين (والشيكات مترجم لأعمار) جعل التعرج من شرائح آمنة تماما.ومع ذلك ، في بعض الأحيان تحتاج إلى تعديل البيانات في شريحة.ثم تحتاج قابل للتغيير شريحة ، ودعا &mut [T]
.يمكنك تغيير البيانات الخاصة بك من خلال هذه الشريحة;لكن هذه الشرائح هي غير مستعارة.لا يمكنك إنشاء شريحتين قابلتين للتغيير في نفس البنية (مصفوفة ، على سبيل المثال) ، لذلك لا يمكنك فعل أي شيء خطير.
لاحظ ، مع ذلك ، أن استخدام transmute()
لتحويل شريحة إلى Slice
أو العكس هو عملية غير آمنة. &[T]
مضمون بشكل ثابت ليكون صحيحا إذا قمت بإنشائه باستخدام الطرق الصحيحة ، مثل الاتصال as_slice()
على Vec
.ومع ذلك ، إنشائه يدويا باستخدام Slice
هيكل ومن ثم تحويلها إلى &[T]
هو عرضة للخطأ ويمكن بسهولة سيغفولت البرنامج الخاص بك ، على سبيل المثال ، عند تعيينه أكثر طول مما هو مخصص في الواقع.