كائن غير قابل للتغيير

في البرمجة الكائنية والبرمجة الوظيفية ، يُعرف الكائن غير القابل للتغيير ( الكائن الذي لا يمكن تغيير حالته بعد إنشائه) بأنه كائن لا يمكن تعديل حالته بعد إنشائه . وهذا يختلف عن الكائن القابل للتغيير، الذي يمكن تعديل حالته بعد إنشائه. في بعض الحالات ، يُعتبر الكائن غير قابل للتغيير حتى لو تغيرت بعض سماته الداخلية، ولكن حالة الكائن تبدو ثابتة من وجهة نظر خارجية. على سبيل المثال، يمكن اعتبار الكائن الذي يستخدم التخزين المؤقت لنتائج العمليات الحسابية المعقدة كائنًا غير قابل للتغيير .

تُعبّر السلاسل النصية وغيرها من الكائنات الملموسة عادةً عن نفسها ككائنات غير قابلة للتغيير لتحسين سهولة القراءة وكفاءة وقت التشغيل في البرمجة كائنية التوجه. كما أن الكائنات غير القابلة للتغيير مفيدة لأنها آمنة بطبيعتها في بيئات متعددة الخيوط . [ 2 ] ومن مزاياها الأخرى أنها أسهل في الفهم والتحليل، وتوفر مستوى أمان أعلى من الكائنات القابلة للتغيير. [ 2 ]

المفاهيم

المتغيرات غير القابلة للتغيير

في البرمجة الإجرائية ، تُعرف القيم المخزنة في متغيرات البرنامج والتي لا يتغير محتواها بالثوابت ، وذلك لتمييزها عن المتغيرات التي يمكن تغييرها أثناء التنفيذ. ومن الأمثلة على ذلك عوامل التحويل من المتر إلى القدم، أو قيمة باي (π) لعدة منازل عشرية.

يمكن حساب الحقول للقراءة فقط عند تشغيل البرنامج (على عكس الثوابت، التي تكون معروفة مسبقًا)، ولكنها لا تتغير أبدًا بعد تهيئتها.

عدم قابلية التغيير الضعيفة مقابل عدم قابلية التغيير القوية

أحيانًا، يُشار إلى بعض حقول الكائن بأنها غير قابلة للتغيير. وهذا يعني أنه لا توجد طريقة لتغيير تلك الأجزاء من حالة الكائن، حتى وإن كانت أجزاء أخرى منه قابلة للتغيير ( غير قابلة للتغيير بشكل ضعيف ). إذا كانت جميع الحقول غير قابلة للتغيير، فإن الكائن يكون غير قابل للتغيير. أما إذا كان الكائن بأكمله غير قابل للتوسيع بواسطة فئة أخرى، فيُسمى الكائن غير قابل للتغيير بشكل كامل . [ 4 ] قد يُساعد هذا، على سبيل المثال، في فرض ثوابت معينة بشكل صريح حول بقاء بيانات معينة في الكائن كما هي طوال دورة حياته. في بعض اللغات، يتم ذلك باستخدام كلمة مفتاحية (مثلًا constفي C++ ، finalوفي Java ) تُحدد الحقل على أنه غير قابل للتغيير. في بعض اللغات الأخرى، يكون الأمر معكوسًا: ففي OCaml ، تكون حقول الكائن أو السجل غير قابلة للتغيير افتراضيًا، ويجب تحديدها صراحةً mutableلتكون كذلك.

إشارات إلى الكائنات

في معظم لغات البرمجة كائنية التوجه ، يُمكن الإشارة إلى الكائنات باستخدام المراجع . ومن أمثلة هذه اللغات: جافا ، وسي++ ، وسي# ، وفي بي.نت ، والعديد من لغات البرمجة النصية ، مثل بيرل ، وبايثون ، وروبي . في هذه الحالة، يُعدّ من المهم معرفة ما إذا كان من الممكن أن تتغير حالة الكائن عند مشاركة الكائنات عبر المراجع.

الإشارة إلى الكائنات مقابل نسخها

إذا كان من المعروف أن الكائن غير قابل للتغيير، يُفضّل إنشاء مرجع له بدلاً من نسخ الكائن بأكمله. يُجرى ذلك لتوفير الذاكرة عن طريق منع تكرار البيانات وتجنب استدعاء الدوال البانية والمدمرة؛ كما يُؤدي ذلك إلى تحسين سرعة التنفيذ.

تُعدّ تقنية نسخ المرجع أكثر صعوبةً في التعامل مع الكائنات القابلة للتغيير، لأنه إذا قام أي مستخدم بتغيير مرجع كائن قابل للتغيير، فسيرى جميع المستخدمين الآخرين لهذا المرجع التغيير. وإذا لم يكن هذا هو التأثير المقصود، فقد يصعب إخطار المستخدمين الآخرين ليستجيبوا بشكل صحيح. في هذه الحالات، يُعدّ النسخ الوقائي للكائن بأكمله بدلاً من المرجع حلاً سهلاً ولكنه مكلف. ويُعدّ نمط المراقب تقنية بديلة للتعامل مع التغييرات التي تطرأ على الكائنات القابلة للتغيير.

النسخ عند الكتابة

تُعدّ تقنية النسخ عند الكتابة (COW) إحدى التقنيات التي تجمع بين مزايا الكائنات القابلة للتغيير وغير القابلة للتغيير ، وهي مدعومة مباشرةً في معظم الأجهزة الحديثة. باستخدام هذه التقنية، عندما يطلب المستخدم من النظام نسخ كائن ما، يقوم النظام ببساطة بإنشاء مرجع جديد يشير إلى نفس الكائن. بمجرد أن يحاول المستخدم تعديل الكائن من خلال مرجع معين، يقوم النظام بإنشاء نسخة حقيقية، وتطبيق التعديل عليها، ثم يُعيّن المرجع ليشير إلى النسخة الجديدة. لا يتأثر المستخدمون الآخرون، لأنهم ما زالوا يشيرون إلى الكائن الأصلي. لذلك، في ظل تقنية النسخ عند الكتابة، يبدو أن جميع المستخدمين يمتلكون نسخة قابلة للتغيير من كائناتهم، مع الحفاظ على مزايا توفير المساحة والسرعة التي توفرها الكائنات غير القابلة للتغيير في حال عدم قيام المستخدمين بتعديل كائناتهم. تحظى تقنية النسخ عند الكتابة بشعبية في أنظمة الذاكرة الافتراضية لأنها تسمح لها بتوفير مساحة الذاكرة مع ضمان التعامل السليم مع أي إجراء قد يقوم به برنامج التطبيق.

التدريب الداخلي

تُعرف ممارسة استخدام المراجع بدلاً من نسخ الكائنات المتطابقة باسم "التخزين المؤقت" . عند استخدام التخزين المؤقت، يُعتبر كائنان متطابقين إذا وفقط إذا كانت مراجعهما، والتي تُمثل عادةً بمؤشرات أو أعداد صحيحة، متطابقة. تقوم بعض لغات البرمجة بذلك تلقائيًا؛ على سبيل المثال، تقوم لغة بايثون بالتخزين المؤقت للسلاسل النصية القصيرة تلقائيًا . إذا كان من المضمون أن تقوم الخوارزمية التي تُنفذ التخزين المؤقت بذلك في كل حالة ممكنة، فإن مقارنة الكائنات للتأكد من تطابقها ستقتصر على مقارنة مؤشراتها، مما يُحقق زيادة كبيرة في السرعة في معظم التطبيقات. (حتى لو لم تكن الخوارزمية شاملة، فإنه لا يزال من الممكن تحسين المسار السريع عندما تكون الكائنات متطابقة وتستخدم نفس المرجع). يُعد التخزين المؤقت مفيدًا بشكل عام للكائنات غير القابلة للتغيير فقط.

أمان الخيوط

تُعدّ الكائنات غير القابلة للتغيير مفيدة في التطبيقات متعددة الخيوط. إذ يمكن لعدة خيوط معالجة البيانات المُمثلة بهذه الكائنات دون القلق من تغييرها بواسطة خيوط أخرى. ولذلك، تُعتبر الكائنات غير القابلة للتغيير أكثر أمانًا في بيئات متعددة الخيوط من الكائنات القابلة للتغيير.

انتهاك عدم قابلية التغيير

لا تعني خاصية عدم التغيير أن الكائن المخزن في ذاكرة الحاسوب غير قابل للكتابة. بل هي بنية برمجية تُستخدم أثناء الترجمة، وتشير إلى ما يمكن للمبرمج فعله من خلال الواجهة العادية للكائن، وليس بالضرورة ما يمكنه فعله بشكل مطلق (على سبيل المثال، عن طريق تجاوز نظام الأنواع أو انتهاك صحة الثوابت في لغتي C أو C++ ).

تفاصيل خاصة باللغة

في لغات بايثون وجافا [ 5 ] : 80 وإطار عمل .NET ، تُعتبر السلاسل النصية كائنات غير قابلة للتغيير. بينما تحتوي كل من جافا وإطار عمل .NET على نسخ قابلة للتغيير من السلاسل النصية. في جافا [ 5 ] : 84 ، تُسمى هذه النسخ ` StringBufferstring` و`string` (نسخ قابلة للتغيير StringBuilderمن جافا String)، وفي .NET تُسمى `string` (نسخة قابلة للتغيير StringBuilderمن .NET String). أما بايثون 3 ، فلديها نوع متغير من السلاسل النصية (بايتات) قابل للتغيير، يُسمى `string` bytearray. [ 6 ]

بالإضافة إلى ذلك، فإن جميع فئات التغليف الأولية في جافا غير قابلة للتغيير.

الأنماط المشابهة هي الواجهة غير القابلة للتغيير والغلاف غير القابل للتغيير .

في لغات البرمجة الوظيفية البحتة ، لا يمكن إنشاء كائنات قابلة للتغيير دون توسيع اللغة (على سبيل المثال عبر مكتبة مراجع قابلة للتغيير أو واجهة دالة خارجية )، لذلك فإن جميع الكائنات غير قابلة للتغيير.

آدا

في لغة Ada ، يتم تعريف أي كائن إما كمتغير (أي قابل للتغيير؛ وهو عادةً الافتراضي الضمني)، أو constant(أي غير قابل للتغيير) عبر constantالكلمة المفتاحية.

type Some_type is new Integer ; -- يمكن أن يكون أي شيء أكثر تعقيدًا x : ​​constant Some_type := 1 ; -- غير قابل للتغيير y : Some_type ; -- قابل للتغيير

تكون معلمات البرنامج الفرعي غير قابلة للتغيير في وضع الإدخال ، وقابلة للتغيير في وضعي الإدخال والإخراج .

الإجراء Do_it ( a : in Integer ; b : in out Integer ; c : out Integer ) is begin -- a is immutable b := b + a ; c := a ; end Do_it ;

سي شارب

في لغة C# ، يمكن فرض عدم قابلية تغيير حقول فئة ما باستخدام readonlyالعبارة [ 7 ] : 239. بفرض عدم قابلية تغيير جميع الحقول، يصبح النوع نوعًا غير قابل للتغيير.

class ImmutableType { public readonly double Value { get ; }public ImmutableType ( double x ) { Value = x ; }public ImmutableType Square () { return new ImmutableType ( Value * Value ); } }

تحتوي لغة C# على سجلات غير قابلة للتغيير. [ 8 ] [ 9 ]

سجل الشخص ( سلسلة الاسم الأول ، سلسلة الاسم الأخير 

لغة سي++

في لغة C++، يسمح تطبيق ثابت صحيحShoppingCart للمستخدم بإنشاء نسخ من الصنف ثم استخدامها إما كـ const(غير قابلة للتغيير) أو قابلة للتغيير، حسب الرغبة، من خلال توفير نسختين مختلفتين من items()الدالة. (لاحظ أنه في لغة C++ ليس من الضروري - بل من المستحيل - توفير مُنشئ مُخصص constللنسخ).

استيراد std ؛باستخدام std :: vector ؛ باستخدام std :: views :: transform ؛class ShoppingCart { private : vector <Merchandise> items ; public : explicit Cart ( const vector <Merchandise> & items ) : items { items } { }vector <Merchandise> & items ( ) { return items ; }const vector <Merchandise> & items ( ) const { return items ; }double computeTotalCost () const { return std :: ranges :: accumulate ( items | transform ([]( const Merchandise & m ) -> double { return m . getPrice (); }), 0.0 ); } };

لاحظ أنه عندما يكون هناك عضو بيانات عبارة عن مؤشر أو مرجع إلى كائن آخر، فمن الممكن تغيير الكائن المشار إليه أو المرجع إليه فقط داخل طريقة غير ثابتة.

توفر لغة C++ أيضًا عدم قابلية التغيير المجردة (على عكس عدم قابلية التغيير على مستوى البت) عبر الكلمة mutableالمفتاحية، والتي تسمح بتغيير متغير عضوconst من داخل طريقة.

استيراد std ؛باستخدام std :: optional ؛ باستخدام std :: vector ؛ باستخدام std :: views :: transform ؛class ShoppingCart { private : vector <Merchandise> items ; mutableoptional <int> totalCost ; public : explicit Cart ( const vector <Merchandise> & items ) : items { items } { }const vector <Merchandise> & items ( ) const { return items ; }دالة حساب التكلفة الإجمالية () ثابتة { إذا ( ! التكلفة الإجمالية ) { التكلفة الإجمالية = std :: ranges :: تراكم ( العناصر | تحويل ([]( const Merchandise & m ) -> double { إرجاع m . getPrice (); }), 0.0 ); } إرجاع * التكلفة الإجمالية ; } };

د

في لغة D ، يوجد مُحدِّدان للأنواع ، هما `include` constو`include` immutable، للمتغيرات التي لا يمكن تغييرها. [ 10 ] على عكس مُحدِّدات الأنواع في لغات C++ و constJava finalوC# readonly، فإن `include` و`include` متعدية وتُطبَّق بشكل متكرر على أي شيء يمكن الوصول إليه من خلال مراجع هذا المتغير. الفرق بين `include` constو`include` immutableهو ما ينطبق عليهما: ` constinclude` هي خاصية للمتغير: قد توجد مراجع قابلة للتغيير للقيمة المُشار إليها، أي أن القيمة يمكن أن تتغير بالفعل. في المقابل، `include` immutableهي خاصية للقيمة المُشار إليها: لا يمكن تغيير القيمة وأي شيء يمكن الوصول إليه منها بشكل متعدٍ (دون الإخلال بنظام الأنواع، مما يؤدي إلى سلوك غير مُعرَّفconst ). يجب وضع علامة `include` أو ` include` على أي مرجع لتلك القيمة immutable. بشكل أساسي، بالنسبة لأي نوع غير مُحدَّد T، const(T)فإن `include` هو الاتحاد المنفصل لـ `include` T(القابل للتغيير) و`include` immutable(T).

class Example { Object mutableField ; // mutable const Object constField ; immutable Object immutableField ; }

بالنسبة Exampleللكائن القابل للتغيير، mutableFieldيمكن الكتابة إليه. أما بالنسبة const(Example)للكائن غير القابل mutableFieldللتغيير، فلا يمكن تعديله، ولكنه يرث خاصية عدم التغيير const؛ immutableFieldويظل غير قابل للتغيير لأنه الضمان الأقوى. بالنسبة للكائن غير القابل immutable(Example)للتغيير، فإن جميع حقوله غير قابلة للتغيير.

في دالة كهذه:

void fn ( Example m , const Example c , immutable Example i ) { // داخل الأقواس }

داخل الأقواس، cقد يشير إلى نفس الكائن m، لذا فإن التغييرات التي تطرأ على mقد تُغير بشكل غير مباشر cأيضًا. كذلك، cقد يشير إلى نفس الكائن i، ولكن بما أن القيمة غير قابلة للتغيير، فلا توجد تغييرات. مع ذلك، لا يمكن لـ mو iأن يشيرا إلى نفس الكائن بشكل صحيح.

في لغة الضمانات، لا يوجد ضمانات للدالة القابلة للتغيير (قد تغير الدالة الكائن)، constوهي ضمان خارجي فقط بأن الدالة لن تغير أي شيء، وهي immutableضمان ثنائي الاتجاه (لن تغير الدالة القيمة ويجب على المستدعي عدم تغييرها).

القيم التي يتم constأو immutableيجب تهيئتها عن طريق التعيين المباشر عند نقطة الإعلان أو عن طريق المُنشئ .

لأن constالمعاملات تتجاهل ما إذا كانت القيمة قابلة للتغيير أم لا، فإن بنية مشابهة، inoutتعمل، بمعنى ما، كمتغير لمعلومات قابلية التغيير. const(S) function(const(T))تُرجع دالة من النوع قيمًا مُحددة النوع للمعاملات القابلة للتغيير، والثابتة، وغير القابلة للتغيير. في المقابل، تُرجع const(S)دالة من النوع للمعاملات القابلة للتغيير ، و للقيم ، و للقيم .inout(S) function(inout(T))STconst(S)const(T)immutable(S)immutable(T)

يؤدي تحويل القيم غير القابلة للتغيير إلى قيم قابلة للتغيير إلى سلوك غير محدد عند التغيير، حتى لو كانت القيمة الأصلية من أصل قابل للتغيير. قد يكون تحويل القيم القابلة للتغيير إلى قيم غير قابلة للتغيير قانونيًا عندما لا تبقى أي مراجع قابلة للتغيير بعد ذلك. "يمكن تحويل تعبير من قابل للتغيير (...) إلى غير قابل للتغيير إذا كان التعبير فريدًا، وكانت جميع التعبيرات التي يشير إليها بشكل متعدٍ إما فريدة أو غير قابلة للتغيير." [ 10 ] إذا لم يتمكن المترجم من إثبات التفرد، فيمكن إجراء التحويل بشكل صريح، ويقع على عاتق المبرمج التأكد من عدم وجود أي مراجع قابلة للتغيير.

هذا النوع stringهو اسم بديل لـ immutable(char)[]، أي شريحة ذاكرة مُحددة النوع تحتوي على أحرف غير قابلة للتغيير. [ 11 ] إنشاء سلاسل فرعية عملية سريعة، إذ تقتصر على نسخ وتعديل مؤشر وحقل طول، وهي آمنة، لأن البيانات الأساسية لا يمكن تغييرها. يمكن لكائنات هذا النوع const(char)[]الإشارة إلى سلاسل نصية، وكذلك إلى مخازن مؤقتة قابلة للتغيير.

يؤدي إنشاء نسخة سطحية من قيمة ثابتة أو غير قابلة للتغيير إلى إزالة الطبقة الخارجية من عدم قابلية التغيير: فنسخ سلسلة نصية غير قابلة للتغيير ( immutable(char[])) يُعيد سلسلة نصية ( immutable(char)[]). يتم نسخ المؤشر غير القابل للتغيير والطول، وتكون النسخ قابلة للتغيير. لم يتم نسخ البيانات المشار إليها، وتحتفظ بمؤهلها، في المثال immutable. يمكن إزالة هذا المؤهل عن طريق إنشاء نسخة أعمق، على سبيل المثال باستخدام dupالدالة .

جافا

يُعدّ مثالًا كلاسيكيًا على الكائن غير القابل للتغيير هو نسخة من Stringفئة Java

String s = "ABC" ; s . toLowerCase (); // هذا لا يُحقق أي شيء!

لا تُغيّر هذه الطريقة toLowerCase()البيانات "ABC" sالموجودة. بدلاً من ذلك، يتم إنشاء كائن String جديد وتزويده بالبيانات "abc" أثناء إنشائه. تُعيد الطريقة مرجعًا إلى كائن String هذا toLowerCase(). لجعل String sيحتوي على البيانات "abc"، يلزم اتباع نهج مختلف.

s = s.toLowerCase ( ) ;

يشير الآن الكائن String sإلى كائن String جديد يحتوي على "abc". لا يوجد في صيغة تعريف فئة String ما يفرض عدم قابليتها للتغيير؛ بل على العكس، لا تؤثر أي من طرق فئة String على البيانات التي يحتويها كائن String، مما يجعله غير قابل للتغيير.

تُستخدم الكلمة المفتاحية final( المذكورة في المقال المفصل ) في تطبيق أنواع البيانات الأولية غير القابلة للتغيير ومراجع الكائنات، [ 12 ] ولكنها لا تستطيع، بمفردها، جعل الكائنات نفسها غير قابلة للتغيير. انظر الأمثلة أدناه:

يمكن إعادة تعيين قيم المتغيرات من النوع الأولي ( intمثل `int` longو` shortint` و`int` وما إلى ذلك) بعد تعريفها. ويمكن منع ذلك باستخدام ` final.

int i = 42 ; // int نوع بيانات أولي i = 43 ; // صحيحfinal int j = 42 ; j = 43 ; // لا يتم تجميع هذا الكود. قيمة j نهائية، لذا لا يمكن إعادة تعيينها.

لا يمكن جعل أنواع المراجع غير قابلة للتغيير بمجرد استخدام الكلمة finalالمفتاحية. finalفهي تمنع إعادة التعيين فقط.

final MyObject m = new MyObject (); // m من نوع مرجعي . m.data = 100 ; // صحيح. يمكننا تغيير حالة الكائن m (m قابل للتغيير، و final لا يغير هذه الحقيقة). m = new MyObject ( ); // لا يتم تجميع هذا الكود. m نهائي، لذا لا يمكن إعادة تعيين قيمته.

تُعتبر جميع الأغلفة الأولية ( Integer, Long, Short, Double, Float, Character, Byte, Boolean) غير قابلة للتغيير. ويمكن تطبيق الفئات غير القابلة للتغيير باتباع بعض الإرشادات البسيطة. [ 13 ]

جافا سكريبت

في لغة جافا سكريبت ، جميع الأنواع الأولية (Undefined، Null، Boolean، Number، BigInt، String، Symbol) غير قابلة للتغيير، ولكن الكائنات المخصصة قابلة للتغيير بشكل عام.

دالة doSomething ( x ) { /* هل تغيير x هنا يغير الأصل؟ */ }; var str = 'a string' ; var obj = { an : 'object' }; doSomething ( str ); // السلاسل النصية والأرقام والأنواع المنطقية غير قابلة للتغيير، تحصل الدالة على نسخة منها doSomething ( obj ); // يتم تمرير الكائنات بالمرجع وهي قابلة للتغيير داخل الدالة doAnotherThing ( str , obj ); // لم يتغير `str`، ولكن قد يكون `obj` قد تغير.

لمحاكاة عدم قابلية التغيير في كائن ما، يمكن تعريف الخصائص على أنها للقراءة فقط (writable: false).

var obj = {}; Object.defineProperty ( obj , 'foo' , { value : ' bar' , writable : false } ) ; obj.foo = 'bar2' ; // يتم تجاهلها بصمت

مع ذلك، لا يزال الأسلوب المذكور أعلاه يسمح بإضافة خصائص جديدة. بدلاً من ذلك، يمكن استخدام Object.freeze لجعل الكائنات الموجودة غير قابلة للتغيير.

var obj = { foo : 'bar' }; Object . freeze ( obj ); obj . foo = 'bars' ; // لا يمكن تعديل الخاصية، يتم تجاهلها بصمت obj . foo2 = 'bar2' ; // لا يمكن إضافة الخاصية، يتم تجاهلها بصمت

مع تطبيق معيار ECMA262 ، أصبح بإمكان جافا سكريبت إنشاء مراجع غير قابلة للتغيير لا يمكن إعادة تعيينها. ومع ذلك، فإن استخدام هذا constالتصريح لا يعني أن قيمة المرجع للقراءة فقط غير قابلة للتغيير، بل يعني فقط أنه لا يمكن تعيين الاسم لقيمة جديدة.

const ALWAYS_IMMUTABLE = true ;try { ALWAYS_IMMUTABLE = false ; } catch ( err ) { console . log ( "لا يمكن إعادة تعيين مرجع غير قابل للتغيير." ); }const arr = [ 1 , 2 , 3 ] ; arr.push ( 4 ); console.log ( arr ) ; // [1, 2, 3, 4 ]

أصبح استخدام الحالة غير القابلة للتغيير اتجاهًا متزايدًا في جافا سكريبت منذ ظهور React ، الذي يفضل أنماط إدارة الحالة الشبيهة بـ Flux مثل Redux . [ 14 ]

بيرل

في لغة بيرل ، يمكن إنشاء فئة غير قابلة للتغيير باستخدام مكتبة Moo ببساطة عن طريق تعريف جميع السمات على أنها للقراءة فقط:

الحزمة غير القابلة للتغيير ؛ استخدم Moo ؛له قيمة => ( هو => 'ro' ، # للقراءة فقط القيمة الافتراضية => 'data' ، # يمكن تجاوزها بتزويد المُنشئ بقيمة : Immutable->new(value => 'something else'); );1 ؛

كان إنشاء فئة غير قابلة للتغيير يتطلب خطوتين: أولاً، إنشاء دوال الوصول (إما تلقائياً أو يدوياً) التي تمنع تعديل سمات الكائن، وثانياً، منع التعديل المباشر لبيانات مثيلات تلك الفئة (عادةً ما يتم تخزين هذا في مرجع تجزئة، ويمكن قفله باستخدام دالة lock_hash الخاصة بـ Hash::Util):

package Immutable ; use strict ; use warnings ; use base qw(Class::Accessor) ; # إنشاء دوال وصول للقراءة فقط __PACKAGE__ -> mk_ro_accessors ( qw(value) ); use Hash::Util 'lock_hash' ;sub new { my $class = shift ; return $class if ref ( $class ); die "يجب أن تكون وسائط new أزواج مفتاح => قيمة\n" unless ( @_ % 2 == 0 ); my %defaults = ( value => 'data' , ); my $obj = { %defaults , @_ , }; bless $obj , $class ; # منع تعديل بيانات الكائن lock_hash %$obj ; } 1 ;

أو باستخدام دالة وصول مكتوبة يدويًا:

الحزمة غير القابلة للتغيير ؛ استخدم الوضع الصارم ؛ استخدم التحذيرات ؛ استخدم Hash::Util 'lock_hash' ؛sub new { my $class = shift ; return $class if ref ( $class ); die "يجب أن تكون وسائط new أزواج مفتاح => قيمة\n" unless ( @_ % 2 == 0 ); my %defaults = ( value => 'data' , ); my $obj = { %defaults , @_ , }; bless $obj , $class ; # منع تعديل بيانات الكائن lock_hash %$obj ; }# دالة وصول للقراءة فقط sub value { my $self = shift ; if ( my $new_value = shift ) { # محاولة تعيين قيمة جديدة die "لا يمكن تعديل هذا الكائن\n" ; } else { return $self -> { value } } } 1 ;

PHP

في لغة PHP، توجد خصائص للقراءة فقط منذ الإصدار 8.1 وفئات للقراءة فقط منذ الإصدار 8.2. [ 15 ] [ 16 ]

فئة BlogData للقراءة فقط { سلسلة عامة $title ;الحالة العامة $status ;public function __construct ( string $title , Status $status ) { $this -> title = $title ; $this -> status = $status ; } }

بايثون

في لغة بايثون ، بعض الأنواع المضمنة (الأرقام، والقيم المنطقية، والسلاسل النصية، والصفوف، والمجموعات المجمدة) غير قابلة للتغيير، بينما تكون الفئات المخصصة قابلة للتغيير عمومًا. لمحاكاة عدم قابلية التغيير في فئة ما، يمكن تجاوز وظائف تعيين وحذف السمات لإثارة استثناءات.

من typing استورد Any و NoReturnclass ImmutablePoint : """صنف غير قابل للتغيير يحتوي على سمتين 'x' و 'y'."""__slots__ : list [ str ] = [ "x" , "y" ]def __setattr__ ( self , * args : tuple [ Any , ... ]) -> NoReturn : raise TypeError ( "لا يمكن تعديل نسخة غير قابلة للتغيير." )__delattr__ : دالة قابلة للاستدعاء [[ Tuple [ Any , ... ]], NoReturn ] = __setattr__def __init__ ( self , x : int , y : int ) -> None : # لم يعد بإمكاننا استخدام self.value = value لتخزين بيانات الكائن # لذلك يجب علينا استدعاء الفئة الأصلية بشكل صريح super () .__ setattr__ ( "x" , x ) super () .__ setattr__ ( "y" , y )

تُتيح دوال المساعدة في المكتبة القياسية collections.namedtuple، typing.NamedTupleالمتوفرة بدءًا من بايثون 3.6، إنشاء فئات بسيطة غير قابلة للتغيير. المثال التالي يُعادل تقريبًا المثال السابق، بالإضافة إلى بعض الميزات الشبيهة بالصفوف:

من typing استورد NamedTuple واستورد collectionsنقطة : NamedTuple = collections.namedtuple ( "نقطة" , [ " س " , "ص" ])# يُنشئ ما يلي كائنًا من نوع NamedTuple مشابهًا للكائن المذكور أعلاه من الفئة Point ( NamedTuple ): x : int y : int

تم تقديم هذه الميزة في بايثون 3.7، dataclassesوهي تسمح للمطورين بمحاكاة عدم قابلية التغيير باستخدام النسخ المجمدة . إذا تم إنشاء فئة بيانات مجمدة، dataclassesفسيتم تجاوزها __setattr__()وإثارة __delattr__()استثناء FrozenInstanceErrorعند استدعائها.

from dataclasses import dataclass@dataclass ( frozen = True ) class Point : x : int y : int

مضرب

يختلف Racket اختلافًا جوهريًا عن تطبيقات Scheme الأخرى بجعل نوع الزوج الأساسي (cons cells) غير قابل للتغيير. بدلاً من ذلك، يوفر Racket نوع زوج قابل للتغيير موازٍ، عبر و ، mconsوما إلى ذلك. بالإضافة إلى ذلك، يدعم Racket العديد من الأنواع غير القابلة للتغيير، مثل السلاسل النصية والمتجهات غير القابلة للتغيير، والتي تُستخدم على نطاق واسع. تكون الهياكل الجديدة غير قابلة للتغيير افتراضيًا، ما لم يُصرّح صراحةً بأن أحد الحقول قابل للتغيير، أو أن الهيكل بأكمله قابل للتغيير.mcarset-mcar!

( struct foo1 ( x, y )) ; جميع الحقول غير قابلة للتغيير ( struct foo2 ( x [ y ]:mutable ]) ; حقل واحد قابل للتغيير ( struct foo3 ( x, y )] :mutable ) ; جميع الحقول قابلة للتغيير

تدعم اللغة أيضًا جداول التجزئة غير القابلة للتغيير، والمنفذة وظيفيًا، والقواميس غير القابلة للتغيير.

الصدأ

يُتيح نظام ملكية البيانات في لغة Rust للمطورين تعريف متغيرات غير قابلة للتغيير، وتمرير مراجع غير قابلة للتغيير. افتراضيًا، تكون جميع المتغيرات والمراجع غير قابلة للتغيير. أما المتغيرات والمراجع القابلة للتغيير، فيتم إنشاؤها صراحةً باستخدام mutالكلمة المفتاحية `.`

العناصر الثابتة في لغة Rust تكون دائماً غير قابلة للتغيير.

// العناصر الثابتة غير قابلة للتغيير دائمًا const ALWAYS_IMMUTABLE : bool = true ;struct MyPair { x : usize , y : usize , }fn main () { // تعريف متغير قابل للتغيير بشكل صريح let mut mutable_obj = MyPair { x : 1 , y : 2 }; mutable_obj . x = 3 ; // صحيحlet mutable_ref = & mut mutable_obj ; mutable_ref.x = 1 ; // صحيحlet immutable_ref = & mutable_obj ; immutable_ref . x = 3 ; // خطأ E0594// افتراضيًا، المتغيرات غير قابلة للتغيير let immutable_obj = MyPair { x : 4 , y : 5 }; immutable_obj . x = 6 ; // خطأ E0596let mutable_ref2 = & mut immutable_obj ; // خطأ E0596let immutable_ref2 = & immutable_obj ; immutable_ref2 . x = 6 ; // خطأ E0594 }

سكالا

في لغة سكالا ، يمكن تعريف أي كيان (بشكل أدق، ربط) على أنه قابل للتغيير أو غير قابل للتغيير: في التصريح، يمكن استخدام val(value) للكيانات غير القابلة للتغيير و var(variable) للكيانات القابلة للتغيير. لاحظ أنه على الرغم من أنه لا يمكن إعادة تعيين الربط غير القابل للتغيير، إلا أنه لا يزال بإمكانه الإشارة إلى كائن قابل للتغيير، ولا يزال من الممكن استدعاء دوال التغيير على هذا الكائن: الربط غير قابل للتغيير، لكن الكائن الأساسي قد يكون قابلاً للتغيير.

على سبيل المثال، مقتطف الشفرة التالي:

فال الحد الأقصى = 100 فار القيمة الحالية = 1

يُعرّف كيانًا غير قابل للتغيير maxValue(يتم استنتاج نوع العدد الصحيح في وقت الترجمة) وكيانًا قابلًا للتغيير باسم currentValue.

بشكل افتراضي، تكون فئات المجموعات مثل List`and` Mapغير قابلة للتغيير، لذا تُعيد دوال التحديث نسخة جديدة بدلاً من تعديل نسخة موجودة. مع أن هذا قد يبدو غير فعال، إلا أن تنفيذ هذه الفئات وضماناتها لعدم قابليتها للتغيير يعني أن النسخة الجديدة يمكنها إعادة استخدام العقد الموجودة، وهو أمر فعال للغاية، خاصة عند إنشاء نسخ. [ 17 ]

انظر أيضاً

مراجع

تحتوي هذه المقالة على بعض المواد من كتاب أنماط تصميم بيرل

  1. "صفة ثابتة - تعريف، صور، نطق، وملاحظات استخدام - قاموس أكسفورد المتقدم للمتعلمين على موقع OxfordLearnersDictionaries.com " . www.oxfordlearnersdictionaries.com
  2. 1 2 3 غوتز وآخرون. التزامن في جافا عمليًا . أديسون ويسلي بروفيشنال، 2006، القسم 3.4. عدم قابلية التغيير
  3. "6.005 — بناء البرمجيات" .
  4. ديفيد أوميرا (أبريل 2003). "الكائنات القابلة للتغيير وغير القابلة للتغيير: تأكد من عدم إمكانية تجاوز الدوال" . جافا رانش . تم الاطلاع عليه بتاريخ 14 مايو 2012. الطريقة المُفضلة هي جعل الفئة نهائية. يُشار إلى هذا أحيانًا باسم "عدم قابلية التغيير القوية". يمنع هذا أي شخص من توسيع فئتك وجعلها قابلة للتغيير عن طريق الخطأ أو عمدًا.
  5. 1 2 بلوخ، جوشوا (2018). "جافا الفعّالة: دليل لغة البرمجة" ( الطبعة الثالثة). أديسون-ويسلي. ISBN  978-0134685991.
  6. "الوظائف المدمجة - وثائق بايثون الإصدار 3.0" . docs.python.org .
  7. سكيت، جون (23 مارس 2019). لغة سي شارب بتفصيل . مانينغ. ISBN 978-1617294532.
  8. "استخدام أنواع السجلات - برنامج تعليمي للغة C# - C#" . learn.microsoft.com . 14 نوفمبر 2023. تم الاطلاع عليه بتاريخ 23 فبراير 2024 .
  9. "سجلات - مرجع C# - C#" . learn.microsoft.com . 25 مايو 2023. تم الاطلاع عليه في 23 فبراير 2024 .
  10. 1 2 مواصفات اللغة D §  18
  11. مواصفات لغة D §  12.16 ( يتم استخداممصطلحي المصفوفة والشريحة بشكل متبادل .)
  12. "كيفية إنشاء فئة وكائن غير قابلين للتغيير في جافا - مثال توضيحي" . Javarevisited.blogspot.co.uk. 2013-03-04 . تم الاطلاع عليه بتاريخ 2014-04-14 .
  13. "الكائنات غير القابلة للتغيير" . javapractices.com . تم الاطلاع عليه بتاريخ 15 نوفمبر 2012 .
  14. "عدم قابلية التغيير في جافا سكريبت: وجهة نظر مخالفة" . ديزالاس وركس .
  15. https://www.php.net/releases/8.1/en.php#readonly_properties
  16. https://www.php.net/releases/8.2/en.php#readonly_classes
  17. "واجهة برمجة تطبيقات المجموعات في سكالا 2.8 - فئات المجموعات غير القابلة للتغيير الملموسة" . Scala-lang.org . تم الاطلاع عليه بتاريخ 14-04-2014 .