الفرق بين المراجعتين لصفحة: «Ruby/assignment»
ط ! تعديل مثال |
ط تصحيح التنسيق |
||
سطر 15: | سطر 15: | ||
بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:<syntaxhighlight lang="ruby"> | بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:<syntaxhighlight lang="ruby"> | ||
1.times do | 1.times do | ||
a = 1 | a = 1 | ||
puts "local variables in the block: #{local_variables.join ", "}" | puts "local variables in the block: #{local_variables.join ", "}" | ||
end | end | ||
puts "no local variables outside the block" if local_variables.empty? | puts "no local variables outside the block" if local_variables.empty? | ||
</syntaxhighlight>وتكون النتيجة طباعة التالي: | </syntaxhighlight>وتكون النتيجة طباعة التالي:<syntaxhighlight lang="text"> | ||
local variables in the block: a | local variables in the block: a | ||
no local variables outside the block | no local variables outside the block | ||
</syntaxhighlight> | |||
بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:<syntaxhighlight lang="ruby"> | بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:<syntaxhighlight lang="ruby"> | ||
a = 0 | a = 0 | ||
1.times do | 1.times do | ||
puts "local variables: #{local_variables.join ", "}" | puts "local variables: #{local_variables.join ", "}" | ||
end | end | ||
</syntaxhighlight>وتكون النتيجة طباعة التّالي: | </syntaxhighlight>وتكون النتيجة طباعة التّالي:<syntaxhighlight lang="text"> | ||
local variables: a | local variables: a | ||
</syntaxhighlight> | |||
ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ. | ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ. | ||
سطر 50: | سطر 42: | ||
يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:<syntaxhighlight lang="ruby"> | يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:<syntaxhighlight lang="ruby"> | ||
a = 0 if false # لا يحصل الإسناد هنا | a = 0 if false # لا يحصل الإسناد هنا | ||
p local_variables # يطبع [:a] | p local_variables # يطبع [:a] | ||
p a # يطبع nil | p a # يطبع nil | ||
</syntaxhighlight>هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:<syntaxhighlight lang="ruby"> | </syntaxhighlight>هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:<syntaxhighlight lang="ruby"> | ||
def big_calculation | def big_calculation | ||
42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت | 42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت | ||
end | end | ||
big_calculation = big_calculation() | big_calculation = big_calculation() | ||
</syntaxhighlight>أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin. | </syntaxhighlight>أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin. | ||
سطر 77: | سطر 64: | ||
وهذا مثال على استخدام متغيّرات الحالة:<syntaxhighlight lang="ruby"> | وهذا مثال على استخدام متغيّرات الحالة:<syntaxhighlight lang="ruby"> | ||
class C | class C | ||
def initialize(value) | def initialize(value) | ||
@instance_variable = value | @instance_variable = value | ||
end | end | ||
def value | def value | ||
@instance_variable | @instance_variable | ||
end | end | ||
end | end | ||
object1 = C.new "some value" | object1 = C.new "some value" | ||
object2 = C.new "other value" | object2 = C.new "other value" | ||
p object1.value # تطبع "some value" | p object1.value # تطبع "some value" | ||
p object2.value # تطبع "other value" | p object2.value # تطبع "other value" | ||
</syntaxhighlight>متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته. | </syntaxhighlight>متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته. | ||
سطر 110: | سطر 86: | ||
مثال:<syntaxhighlight lang="ruby"> | مثال:<syntaxhighlight lang="ruby"> | ||
class A | class A | ||
@@class_variable = 0 | @@class_variable = 0 | ||
def value | def value | ||
@@class_variable | @@class_variable | ||
end | end | ||
def update | def update | ||
@@class_variable = @@class_variable + 1 | @@class_variable = @@class_variable + 1 | ||
end | end | ||
end | end | ||
class B < A | class B < A | ||
def update | def update | ||
@@class_variable = @@class_variable + 2 | @@class_variable = @@class_variable + 2 | ||
end | end | ||
end | end | ||
a = A.new | a = A.new | ||
b = B.new | b = B.new | ||
puts "A value: #{a.value}" | puts "A value: #{a.value}" | ||
puts "B value: #{b.value}" | puts "B value: #{b.value}" | ||
</syntaxhighlight>وعند تنفيذه يطبع التّالي: | </syntaxhighlight>وعند تنفيذه يطبع التّالي:<syntaxhighlight lang="text"> | ||
A value: 0 | A value: 0 | ||
B value: 0 | B value: 0 | ||
</syntaxhighlight> | |||
وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:<syntaxhighlight lang="ruby"> | وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:<syntaxhighlight lang="ruby"> | ||
puts "update A" | puts "update A" | ||
a.update | a.update | ||
puts "A value: #{a.value}" | puts "A value: #{a.value}" | ||
puts "B value: #{b.value}" | puts "B value: #{b.value}" | ||
puts "update B" | puts "update B" | ||
b.update | b.update | ||
puts "A value: #{a.value}" | puts "A value: #{a.value}" | ||
puts "B value: #{b.value}" | puts "B value: #{b.value}" | ||
puts "update A" | puts "update A" | ||
a.update | a.update | ||
puts "A value: #{a.value}" | puts "A value: #{a.value}" | ||
puts "B value: #{b.value}" | puts "B value: #{b.value}" | ||
</syntaxhighlight>وتكون النتيجة: | </syntaxhighlight>وتكون النتيجة:<syntaxhighlight lang="text"> | ||
update A | update A | ||
A value: 1 | A value: 1 | ||
B value: 1 | B value: 1 | ||
update B | update B | ||
A value: 3 | A value: 3 | ||
B value: 3 | B value: 3 | ||
update A | update A | ||
A value: 4 | A value: 4 | ||
B value: 4 | B value: 4 | ||
</syntaxhighlight> | |||
عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError. | عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError. | ||
سطر 203: | سطر 142: | ||
مثال:<syntaxhighlight lang="ruby"> | مثال:<syntaxhighlight lang="ruby"> | ||
$global = 0 | $global = 0 | ||
class C | class C | ||
puts "in a class: #{$global}" | puts "in a class: #{$global}" | ||
def my_method | def my_method | ||
puts "in a method: #{$global}" | puts "in a method: #{$global}" | ||
$global = $global + 1 | $global = $global + 1 | ||
$other_global = 3 | $other_global = 3 | ||
end | end | ||
end | end | ||
C.new.my_method | C.new.my_method | ||
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}" | puts "at top-level, $global: #{$global}, $other_global: #{$other_global}" | ||
</syntaxhighlight>والنتيجة: | </syntaxhighlight>والنتيجة:<syntaxhighlight lang="text"> | ||
in a class: 0 | in a class: 0 | ||
in a method: 0 | in a method: 0 | ||
at top-level, $global: 1, $other_global: 3 | at top-level, $global: 1, $other_global: 3 | ||
</syntaxhighlight> | |||
المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil. | المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil. | ||
سطر 238: | سطر 165: | ||
يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:<syntaxhighlight lang="ruby"> | يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:<syntaxhighlight lang="ruby"> | ||
class C | class C | ||
def value=(value) | def value=(value) | ||
@value = value | @value = value | ||
end | end | ||
end | end | ||
c = C.new | c = C.new | ||
c.value = 42 | c.value = 42 | ||
</syntaxhighlight>استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:<syntaxhighlight lang="ruby"> | </syntaxhighlight>استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:<syntaxhighlight lang="ruby"> | ||
سطر 258: | سطر 179: | ||
عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.<syntaxhighlight lang="ruby"> | عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.<syntaxhighlight lang="ruby"> | ||
class C | class C | ||
attr_accessor :value | attr_accessor :value | ||
def my_method | def my_method | ||
value = 42 | value = 42 | ||
puts "local_variables: #{local_variables.join ", "}" | puts "local_variables: #{local_variables.join ", "}" | ||
puts "@value: #{@value.inspect}" | puts "@value: #{@value.inspect}" | ||
end | end | ||
end | end | ||
C.new.my_method | C.new.my_method | ||
</syntaxhighlight>وتكون النتيجة طباعة التّالي: | </syntaxhighlight>وتكون النتيجة طباعة التّالي:<syntaxhighlight lang="text"> | ||
local_variables: value | local_variables: value | ||
@value: nil | @value: nil | ||
</syntaxhighlight> | |||
لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:<syntaxhighlight lang="ruby"> | لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:<syntaxhighlight lang="ruby"> | ||
class C | class C | ||
attr_accessor :value | attr_accessor :value | ||
def my_method | def my_method | ||
self.value = 42 | self.value = 42 | ||
puts "local_variables: #{local_variables.join ", "}" | puts "local_variables: #{local_variables.join ", "}" | ||
puts "@value: #{@value.inspect}" | puts "@value: #{@value.inspect}" | ||
end | end | ||
end | end | ||
C.new.my_method | C.new.my_method | ||
</syntaxhighlight>وتكون النتيجة: | </syntaxhighlight>وتكون النتيجة:<syntaxhighlight lang="text"> | ||
local_variables: | local_variables: | ||
@value: 42 | @value: 42 | ||
</syntaxhighlight> | |||
== الإسناد المختصر == | == الإسناد المختصر == | ||
يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:<syntaxhighlight lang="ruby"> | يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:<syntaxhighlight lang="ruby"> | ||
a = 1 | a = 1 | ||
a += 2 | a += 2 | ||
p a # تطبع 3 | p a # تطبع 3 | ||
وهذا يكافئ: | وهذا يكافئ: | ||
a = 1 | a = 1 | ||
a = a + 2 | a = a + 2 | ||
p a # تطبع 3 | p a # تطبع 3 | ||
</syntaxhighlight>وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >> | </syntaxhighlight>وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >> | ||
سطر 324: | سطر 221: | ||
مثال:<syntaxhighlight lang="ruby"> | مثال:<syntaxhighlight lang="ruby"> | ||
a ||= 0 | |||
a &&= 1 | a &&= 1 | ||
p a # تطبع 1 | p a # تطبع 1 | ||
</syntaxhighlight>لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0 | |||
لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0 | |||
== إسناد المصفوفات ضمنيًّا == | == إسناد المصفوفات ضمنيًّا == | ||
يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:<syntaxhighlight lang="ruby"> | يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:<syntaxhighlight lang="ruby"> | ||
a = 1, 2, 3 | a = 1, 2, 3 | ||
p a #[1, 2, 3] تطبع | |||
p a # | |||
</syntaxhighlight>وهكذا يتمّ إنشاء مصفوفة ضمنيًّا. | </syntaxhighlight>وهكذا يتمّ إنشاء مصفوفة ضمنيًّا. | ||
يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:<syntaxhighlight lang="ruby"> | يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:<syntaxhighlight lang="ruby"> | ||
a = *[1, 2, 3] | a = *[1, 2, 3] | ||
p a #[1, 2, 3] تطبع | |||
p a # | |||
</syntaxhighlight>كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:<syntaxhighlight lang="ruby"> | </syntaxhighlight>كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:<syntaxhighlight lang="ruby"> | ||
a = 1, *[2, 3] | a = 1, *[2, 3] | ||
p a #[1, 2, 3] تطبع | |||
p a # | |||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 353: | سطر 243: | ||
يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:<syntaxhighlight lang="ruby"> | يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:<syntaxhighlight lang="ruby"> | ||
a, b = 1, 2 | a, b = 1, 2 | ||
p a: a, b: b #{:a=>1, :b=>2} تطبع | |||
p a: a, b: b # | |||
</syntaxhighlight>وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:<syntaxhighlight lang="ruby"> | </syntaxhighlight>وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:<syntaxhighlight lang="ruby"> | ||
def value=(value) | def value=(value) | ||
p assigned: value | p assigned: value | ||
end | end | ||
self.value, $global = 1, 2 #{:assigned=>1} تطبع | |||
self.value, $global = 1, 2 # | |||
p $global # تطبع 2 | p $global # تطبع 2 | ||
</syntaxhighlight>كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:<syntaxhighlight lang="ruby"> | </syntaxhighlight>كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:<syntaxhighlight lang="ruby"> | ||
old_value = 1 | old_value = 1 | ||
new_value, old_value = old_value, 2 | new_value, old_value = old_value, 2 | ||
p new_value: new_value, old_value: old_value | p new_value: new_value, old_value: old_value | ||
#{:new_value=>1, :old_value=>2} تطبع | |||
# | |||
</syntaxhighlight>في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:<syntaxhighlight lang="ruby"> | </syntaxhighlight>في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:<syntaxhighlight lang="ruby"> | ||
a, b = 1, 2, 3 | a, b = 1, 2, 3 | ||
p a: a, b: b #{:a=>1, :b=>2} تطبع | |||
p a: a, b: b # | |||
</syntaxhighlight>يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:<syntaxhighlight lang="ruby"> | </syntaxhighlight>يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:<syntaxhighlight lang="ruby"> | ||
a, *b = 1, 2, 3 | a, *b = 1, 2, 3 | ||
p a: a, b: b #{:a=>1, :b=>[2, 3]} تطبع | |||
p a: a, b: b # | |||
</syntaxhighlight>ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:<syntaxhighlight lang="ruby"> | </syntaxhighlight>ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:<syntaxhighlight lang="ruby"> | ||
*a, b = 1, 2, 3 | *a, b = 1, 2, 3 | ||
p a: a, b: b #{:a=>[1, 2], :b=>3} تطبع | |||
p a: a, b: b # | |||
</syntaxhighlight>لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد. | </syntaxhighlight>لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد. | ||
سطر 390: | سطر 269: | ||
كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:<syntaxhighlight lang="ruby"> | كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:<syntaxhighlight lang="ruby"> | ||
(a, b) = [1, 2] | (a, b) = [1, 2] | ||
p a: a, b: b #{:a=>1, :b=>2} تطبع | |||
p a: a, b: b # | |||
</syntaxhighlight>يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:<syntaxhighlight lang="ruby"> | </syntaxhighlight>يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:<syntaxhighlight lang="ruby"> | ||
a, (b, c) = 1, [2, 3] | a, (b, c) = 1, [2, 3] | ||
p a: a, b: b, c: c #{:a=>1, :b=>2, :c=>3} تطبع | |||
p a: a, b: b, c: c # | |||
</syntaxhighlight>وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:<syntaxhighlight lang="ruby"> | </syntaxhighlight>وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:<syntaxhighlight lang="ruby"> | ||
a, (b, *c), *d = 1, [2, 3, 4], 5, 6 | a, (b, *c), *d = 1, [2, 3, 4], 5, 6 | ||
p a: a, b: b, c: c, d: d | p a: a, b: b, c: c, d: d | ||
#{:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]} تطبع | |||
# | |||
</syntaxhighlight> | </syntaxhighlight> | ||
مراجعة 20:38، 15 نوفمبر 2018
الإسناد في لغة روبي
للإسناد في لغة روبي نستخدم رمز المساواة =، ففي المثال التّالي يُسنَد الرّقم 5 إلى المتغيّر المحلّي v:
v = 5
فالإسناد يُنشئ متغيّرًا محلّيًا جديدًا إذا لم يكن قد عُرِّفَ من قبل.
أسماء المتغيّرات المحليّة
اسم المتغيّر المحلّي يجب أن يبدأ بحرف صغير من مجموعة المحارف US-ASCII أو من مجموعة المحارف التي تُمثَّل باستخدام ثمان خانات ثنائيّة 8-bits. وبشكلٍ عام فإنّ أسماء المتغيّرات المحلّية متوافقة مع US-ASCII كون الأزرار التي تستخدم لكتابتها موجودة في جميع لوحات المفاتيح.
(عمومًا جميع البرامج المكتوبة بلغة روبي يجب أن تستخدم محارفًا متوافقة مع مجموعة المحارف US-ASCII. في مجموعات محارف كهذه، إذا كان البت الثامن بقيمة 1 فهذا يدلّ على أنّ المحرف ينتمي للمحارف الموسّعة extended character، ولغة روبي تسمح أن تحتوي أسماء المتغيّرات هذا النوع من المحارف.)
كما يُمكن لاسم المتحوّل أن يحتوي على حروفًا وأرقامًا ورمز الشرطة السفليّة underscore "_".
نطاق المتغيّرات المحليّة
بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:
1.times do
a = 1
puts "local variables in the block: #{local_variables.join ", "}"
end
puts "no local variables outside the block" if local_variables.empty?
وتكون النتيجة طباعة التالي:
local variables in the block: a
no local variables outside the block
بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:
a = 0
1.times do
puts "local variables: #{local_variables.join ", "}"
end
وتكون النتيجة طباعة التّالي:
local variables: a
ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ.
انظر أيضًا فقرة النواة-المتغيّرات المحليّة، لكن انتبه إلى أنّ الحلقات من نوع for لا تنشئ نطاقًا خاصًّا بها كما هو الحال في الكتل البرمجيّة.
التوابع والمتغيّرات المحليّة
أسماء المتغيّرات المحليّة والتوابع في لغة روبي متماثلة تقريبًا. فإذا عرّفت اسمًا دون أن تسندَ إليه أيّ قيمة فسيُعدّ في اللّغة على أنّه تابع. وبمجرّد أن تُسند إليه قيمة فسيُعدّ متغيّرًا.
يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:
a = 0 if false # لا يحصل الإسناد هنا
p local_variables # يطبع [:a]
p a # يطبع nil
هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:
def big_calculation
42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت
end
big_calculation = big_calculation()
أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin.
يمكنك أيضًا أن تُؤكّد على استدعاء التابع وذلك باستخدام أقواس فارغة كما يظهر في المثال، أو باستخدام مستقبِل محدّد مثل self. لكنّ الطّريقة الثّانية قد تسبب ظهور خطأ NameError إذا كان التابع غير متاح للاستدعاء العام (أي أنه ليس تابع عام).
وهناك حالة أخرى شائعة قد تسبّب التباسًا وتحصل عند استخدام if كالتّالي:
p a if a = 0.zero?
فبدلًا من طباعة "true" سيظهر خطأ NameError, undefined local variable or method 'a'. والسّبب في ذلك يعود إلى أنّ اللغة ترى المتغير a الذي قبل if أوّلًا قبل المتغير a الآخر وتحسب أنّك تريد استدعاء تابع، ثمّ إذا مرّت على المتغير a الآخر فستفترض أنّك تريد الإشارة إلى تابع محليّ.
هذا اللبس يحصل لأنّ تنفيذ العبارة البرمجيّة يحصل بعكس الترتيب المنشود، فالإسناد يتمّ أوّلًا ثمّ يحصل استدعاء لتابع غير موجود.
متغيّرات الحالة Instance Variables
وهي متغيّرات تُشارَك عبر كلّ التوابعّ التابعة لنفس الكائن. هذه المتغيّرات يجب أن تبدأ بالرّمز @، وعدا ذلك فهي تتبع نفس القواعد في تسميّة المتغيّرات المحليّة. وطالما أنّها تبدأ بالرّمز @ فيُمكن للحرف الثّاني أن يكون حرفًا كبيرًا (upper case).
وهذا مثال على استخدام متغيّرات الحالة:
class C
def initialize(value)
@instance_variable = value
end
def value
@instance_variable
end
end
object1 = C.new "some value"
object2 = C.new "other value"
p object1.value # تطبع "some value"
p object2.value # تطبع "other value"
متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته.
يمكن لتابع value أن يصل إلى القيمة التي ضُبِطَت في التابع initialize، وذلك فقط للكائن نفسه.
متغيّرات الأصناف Class Variables
وهي متغيّرات مشتركة بين الصنف والأصناف المتفرّعة منه والكائنات المتولّدة عنه.
يجب أن يبدأ متغيّر الصنف بالرمزين @@، وتتمة الاسم تتبع لنفس أسلوب تسمية متغيّرات الحالة.
مثال:
class A
@@class_variable = 0
def value
@@class_variable
end
def update
@@class_variable = @@class_variable + 1
end
end
class B < A
def update
@@class_variable = @@class_variable + 2
end
end
a = A.new
b = B.new
puts "A value: #{a.value}"
puts "B value: #{b.value}"
وعند تنفيذه يطبع التّالي:
A value: 0
B value: 0
وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:
puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update B"
b.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
وتكون النتيجة:
update A
A value: 1
B value: 1
update B
A value: 3
B value: 3
update A
A value: 4
B value: 4
عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError.
لاحظ أنّ الأصناف لديها أيضًا متغيّرات حالة وذلك لأنّ الأصناف هي كائنات كذلك، لذلك حاول ألّا تخلط بين متغيّرات الأصناف ومتغيّرات الحالة.
المتغيّرات العامّة Global Variables
المتغيّرات العامّة يمكن الوصول إليها في كلّ مكان وهي تبدأ بالرّمز $ وباقي الاسم يتبع نفس أسلوب تسمية متغيّرات الحالة.
مثال:
$global = 0
class C
puts "in a class: #{$global}"
def my_method
puts "in a method: #{$global}"
$global = $global + 1
$other_global = 3
end
end
C.new.my_method
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"
والنتيجة:
in a class: 0
in a method: 0
at top-level, $global: 1, $other_global: 3
المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil.
هناك بعض المتغيّرات العامّة المعرّفة مسبقًا في لغة روبي والتي قد تؤدّي أدوارًا مختلفة حسب السّياق كما هو الحال بالنّسبة لمتغيّرات المطابقة في التعابير النمطية (regular expressions)، وأحيانًا يكون لهذه المتغيّرات العامّة تأثيرات جانبيّة عندما يتمّ الإسناد إليها. لمزيد من التّفاصيل راجع الدّليل الخاص بالمتغيّرات العامّة.
دوالّ الإسناد
يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:
class C
def value=(value)
@value = value
end
end
c = C.new
c.value = 42
استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:
class C
attr_accessor :value
end
عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.
class C
attr_accessor :value
def my_method
value = 42
puts "local_variables: #{local_variables.join ", "}"
puts "@value: #{@value.inspect}"
end
end
C.new.my_method
وتكون النتيجة طباعة التّالي:
local_variables: value
@value: nil
لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:
class C
attr_accessor :value
def my_method
self.value = 42
puts "local_variables: #{local_variables.join ", "}"
puts "@value: #{@value.inspect}"
end
end
C.new.my_method
وتكون النتيجة:
local_variables:
@value: 42
الإسناد المختصر
يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:
a = 1
a += 2
p a # تطبع 3
وهذا يكافئ:
a = 1
a = a + 2
p a # تطبع 3
وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >>
ومن الممكن أيضًا استخدام =|| وفي هذه الحالة يتمّ الإسناد فقط إذا كانت القيمة nil أو false، وبالمثل يمكن استخدام =&& فيتمّ الإسناد فقط إذا لم تكن القيمة nil أو false.
مثال:
a ||= 0
a &&= 1
p a # تطبع 1
لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0
إسناد المصفوفات ضمنيًّا
يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:
a = 1, 2, 3
p a #[1, 2, 3] تطبع
وهكذا يتمّ إنشاء مصفوفة ضمنيًّا. يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:
a = *[1, 2, 3]
p a #[1, 2, 3] تطبع
كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:
a = 1, *[2, 3]
p a #[1, 2, 3] تطبع
الإسناد المتعدّد
يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:
a, b = 1, 2
p a: a, b: b #{:a=>1, :b=>2} تطبع
وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:
def value=(value)
p assigned: value
end
self.value, $global = 1, 2 #{:assigned=>1} تطبع
p $global # تطبع 2
كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:
old_value = 1
new_value, old_value = old_value, 2
p new_value: new_value, old_value: old_value
#{:new_value=>1, :old_value=>2} تطبع
في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:
a, b = 1, 2, 3
p a: a, b: b #{:a=>1, :b=>2} تطبع
يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:
a, *b = 1, 2, 3
p a: a, b: b #{:a=>1, :b=>[2, 3]} تطبع
ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:
*a, b = 1, 2, 3
p a: a, b: b #{:a=>[1, 2], :b=>3} تطبع
لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد.
تفكيك المصفوفات
كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:
(a, b) = [1, 2]
p a: a, b: b #{:a=>1, :b=>2} تطبع
يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:
a, (b, c) = 1, [2, 3]
p a: a, b: b, c: c #{:a=>1, :b=>2, :c=>3} تطبع
وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:
a, (b, *c), *d = 1, [2, 3, 4], 5, 6
p a: a, b: b, c: c, d: d
#{:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]} تطبع
مصادر