ماڈیول اسباق (2/2)
اسمارٹ پوائنٹرز: باکس اور آر سی
ایک سمارٹ پوائنٹر ایک ڈیٹا ڈھانچہ ہے جو پوائنٹر کی طرح برتاؤ کرتا ہے، لیکن اس میں میٹا ڈیٹا اور اضافی صلاحیتیں ہوتی ہیں (جیسے حوالہ شمار یا خودکار میموری کا انتظام)۔
زنگ میں، عام حوالہ جات (جیسے &) صرف ڈیٹا لیتے ہیں۔ دوسری طرف، اسمارٹ پوائنٹرز اکثر اس ڈیٹا کے مالک ہوتے ہیں جس کی وہ نشاندہی کرتے ہیں۔ عام مثالوں میں String اور Vec<T> شامل ہیں، لیکن معیاری لائبریری دیگر خصوصی کتابیں فراہم کرتی ہے۔
ہیپ ایلوکیشن کے لیے باکس<T>
سب سے آسان سمارٹ پوائنٹر Box<T> ہے، جو اسٹیک کے بجائے ہیپ پر ڈیٹا اسٹور کرتا ہے۔ ڈھیر پر مختص کردہ ڈیٹا کا صرف پوائنٹر باقی ہے۔
یہ بنیادی طور پر مندرجہ ذیل صورتوں میں استعمال کیا جاتا ہے:
- جب آپ کے پاس ایک قسم ہے جس کا سائز مرتب کرنے کے وقت معلوم نہیں ہوسکتا ہے (جیسے ایک تکراری قسم)، اور آپ اس قسم کی قدر کو ایسے سیاق و سباق میں استعمال کرنا چاہتے ہیں جس کے لیے درست سائز کی ضرورت ہو۔
- جب آپ ڈیٹا کی ایک بڑی مقدار کو کاپی کیے بغیر اس کی ملکیت منتقل کرنا چاہتے ہیں۔
بنیادی مثال:
fn main() {
let b = Box::new(5); // allocates the value 5 on the heap
println!("b = {}", *b); // dereferences with * to read the value
}تکراری اقسام اور نقصانات کی فہرستیں۔
ایک تکراری قسم ایک قسم ہے جو اس کی تعریف کے حصے کے طور پر خود کی قدر پر مشتمل ہوسکتی ہے۔ مورچا کو کمپائل کے وقت کسی قسم کا صحیح سائز معلوم ہونا چاہیے۔ چونکہ تکراری قسم کی گہرائی لامحدود ہوسکتی ہے، اس لیے مرتب کرنے والا ایک خرابی پیدا کرتا ہے جب تک کہ آپ ایک باکس (جس کا سائز مقررہ ہے، کیونکہ یہ ایک پوائنٹر ہے):
enum List {
Cons(i32, Box<List>),
Nil,
}Rc<T>: حوالہ گنتی
ایسے معاملات ہیں جہاں ایک واحد قدر کے متعدد مالکان ہوسکتے ہیں۔ Rc<T> (حوالہ شمار شدہ) سمارٹ پوائنٹر کسی قدر کے حوالہ جات کی تعداد کو ٹریک کرتا ہے تاکہ یہ تعین کیا جا سکے کہ آیا قدر اب بھی استعمال میں ہے۔ اگر گنتی صفر تک گر جاتی ہے، تو وسائل کو محفوظ طریقے سے ڈیلوکٹ کیا جاتا ہے۔
[!نوٹ]
Rc<T>صرف سنگل تھریڈ والے منظرناموں کے لیے موزوں ہے۔ ملٹی تھریڈڈ (ایک ساتھ) منظرناموں کے لیے، آپ کوArc<T>(ایٹمک حوالہ شمار شدہ) استعمال کرنا چاہیے۔
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a); // increments the reference count to 2
println!("References: {}", Rc::strong_count(&a));
}خود ہی آزمائیں۔
مشق 1: باکس کے ساتھ ہیپ ایلوکیشن
Box::new کا استعمال کرتے ہوئے ہیپ پر 42 کی عددی قدر مختص کریں اور اسے val نامی متغیر کو تفویض کریں۔ اس کے بعد، باکس میں ذخیرہ شدہ قدر کو * آپریٹر کے ساتھ واضح طور پر ڈیریفرنس کرکے پرنٹ کریں۔
اشارہ دکھائیں۔
قدر کو ہیپ میں ذخیرہ کرنے کے لیے `let val = Box::new(42);` استعمال کریں اور `println!` کے اندر `*val` کے ساتھ اس کا حوالہ دیں۔
3 کوششوں کے بعد حل دستیاب ہے۔
مشق 2: تکراری ڈیٹا کا ڈھانچہ (کونس لسٹ)
دو قسموں پر مشتمل فہرست کے نام سے ایک تکراری اینوم کی وضاحت کریں: Cons جو ایک ٹوپل کو لپیٹتا ہے (i32، Box<List>)، اور Nil جو فہرست کے آخر کی نمائندگی کرتا ہے۔ مرکزی فنکشن میں، ایک منسلک فہرست کو فوری بنائیں جس میں عنصر 1 ہو جس کے بعد Nil ہو۔
اشارہ دکھائیں۔
enum کو `enum List { Cons(i32, Box<List>), Nil }` کے طور پر قرار دیا گیا ہے۔ فہرست کو 'List::cons(1, Box::new(List::Nil))' کے ساتھ انسٹینٹیٹ کریں۔
3 کوششوں کے بعد حل دستیاب ہے۔
مشق 3: Rc کے ساتھ ملکیت کا اشتراک کرنا
متغیر a میں قدر 100 پر مشتمل مشترکہ عدد بنانے کے لیے std::rc::Rc استعمال کریں۔ Rc::clone کا استعمال کرتے ہوئے حوالہ کو متغیر b میں کلون کریں۔ آخر میں، Rc::strong_count فنکشن کا استعمال کرتے ہوئے فعال حوالوں کی گنتی پرنٹ کریں۔
اشارہ دکھائیں۔
`Rc::new(100)`کے ساتھ قدر بنائیں۔`Rc::clone(&a)`کے ساتھ کلون کریں اور`Rc::strong_count(&a)` کے ساتھ مالک کی تعداد دکھائیں۔
3 کوششوں کے بعد حل دستیاب ہے۔