انتقل إلى المحتوى الرئيسي

مؤشر

نموذج Wave الصريح لنوع الذاكرة

يعتمد تصميم مؤشر Wave على نموذج Wave الصريح لنوع الذاكرة. يهدف هذا النموذج إلى تعريف المؤشرات والمصفوفات كنوع ذاكرة صريح على مستوى اللغة، وليس كتريك نحوي أو تجريد مكتبي.

وفقًا لهذا التصميم، يتم التعبير عن المؤشر في Wave كنوع في شكل ptr<T>، مما يوضح أنه نوع يشير إلى عنوان الذاكرة الذي يحتوي على قيمة نوع معين T. يسمح هذا النهج بالتعامل مع المؤشر كجزء من نظام النوع، وليس كعامل أو بناء نحوي للتصريح، مما يسمح بتعبير بنية الذاكرة بشكل أكثر وضوحًا واتساقًا.


في Wave، المؤشر هو نوع مصرح يتخذ شكل ptr<T>. يتم اكتساب العنوان باستخدام & و غير المرجعية باستخدام deref.

البيان والتعريف

var x: i32 = 10;
var p: ptr<i32> = &x;

يمكن تداخل نوع المؤشر.

var p1: ptr<i32> = &x;
var p2: ptr<ptr<i32>> = &p1;

غير المرجعية

var x: i32 = 10;
var p: ptr<i32> = &x;

println("{}", deref p); // 10
deref p = 20;
println("{}", x); // 20

قواعد النص الحرفي null

null هو نص حرفي رسمي. ليس معرفاً ولا يمكن استخدامه كاسم متغير.

قواعد أساسية:

  • يمكن إسناد null فقط إلى الكيان ptr<T>.
  • لا يمكن إسنادها إلى الأنواع الغير مؤشرة مثل i32 و bool و array<...>.
  • لا يمكن تهيئة مؤشر باستخدام الأعداد الصحيحة النصية (0, 123, -1 إلخ). استخدم null بشكل صريح.
var p: ptr<i32> = null;
var arrp: ptr<array<i32, 3>> = null;

// var n: i32 = null; // ERROR
// var b: bool = null; // ERROR

حسابات المؤشر

يدعم Wave الحسابات المؤشر التالية.

  • ptr + int: التقدم في المؤشر المعتمد على GEP
  • ptr + int: نفس السلوك
  • int + ptr: التراجع في المؤشر المعتمد على GEP
  • ptr - ptr: حساب الفرق بالبايت لـ i64

نقطة:

  • يتحرك ptr<T> +/- n بمقدار حجم T (sizeof(T)).
  • أي ptr<i32> + 3 تعادل التحرك بمقدار +12 بايت.
var base: ptr<i32> = 0x1000 as ptr<i32>;

var p1: ptr<i32> = base + 3; // 0x1000 + 12
var p2: ptr<i32> = 2 + base; // 0x1000 + 8
var p3: ptr<i32> = base - 1; // 0x1000 - 4

var diff: i64 = p1 - base; // 12 (byte diff)

مقارنة المؤشر

يمكن استخدام المؤشرات للمقارنة.

if (p == null) { ... }
if (p != null) { ... }
if (p1 == p2) { ... }

العلاقة مع المصفوفات

مصفوفة المؤشرات:

var a: i32 = 10;
var b: i32 = 20;
var arr: array<ptr<i32>, 2> = [&a, &b];
println("{} {}", deref arr[0], deref arr[1]);

مؤشر المصفوفة:

var p: ptr<array<i32, 3>> = &[1, 2, 3];
if (p != null) {
println("{}", deref p[1]);
}

ملاحظة حول الأمان

لا تعتمد Wave حاليًا على نموذج أمان المؤشرات القائم على الملكية/العمر مثل Rust. لذا، فهي لا تمنع إلغاء المرجعية التلقائي لـ null. يوصى بوضع نمط يتضمن تحققا صريحا من deref قبل null.