فهم byref و ref و &
-
14-11-2019 - |
سؤال
حسنًا، لقد أدركت أن F# قادر على إدارة المراجع (نوع من المراجع مثل C++).يتيح ذلك إمكانية تغيير قيمة المعلمات التي تم تمريرها في الوظائف كما يمكّن المبرمج من إرجاع أكثر من قيمة واحدة.ولكن إليك ما أحتاج إلى معرفته:
الكلمة المفتاحية المرجعية:الكلمة الرئيسية
ref
يتم استخدامه لإنشاء مرجع من قيمة إلى تلك القيمة من النوع المستنتج.لذاlet myref = ref 10
هذا يعني أن F# سيقوم بإنشاء كائن من النوع
Ref<int>
وضع هناك (في الحقل القابل للتغيير) myint 10
.نعم.لذلك أفترض ذلك
ref
يتم استخدامه لإنشاء مثيلاتRef<'a>
يكتب.هل هذا صحيح؟قيمة الوصول:من أجل الوصول إلى القيمة المخزنة في المرجع يمكنني القيام بذلك:
let myref = ref 10 let myval = myref.Value let myval2 = !myref
بينما ال
:=
يتيح لي عامل التشغيل فقط تعديل القيمة مثل هذا:let myref = ref 10 myref.Value <- 30 myref := 40
لذا
!
(بانغ) يتجاهل مرجعي.و:=
تحريره.وأفترض أن هذا صحيح أيضا.& المشغل:ماذا يفعل هذا المشغل؟هل سيتم تطبيقه على نوع مرجعي؟لا، أعتقد أنه يجب تطبيقه على قيمة قابلة للتغيير وهذا ما يُرجعه؟المرجع؟العنوان؟في حالة استخدام التفاعلية:
let mutable mutvar = 10;; &a;;
السطر الأخير يلقي خطأ لذلك لا أفهم ما هو
&
المشغل هو ل.بواسطةالمرجع:ماذا عن
byref
؟هذا مهم جدًا بالنسبة لي، لكنني أدرك أنني لا أفهمه.أفهم أنه يتم استخدامه في الوظيفة المتعلقة بتمرير المعلمة.يستخدم المرء byref عندما يريد إمكانية تحرير القيمة التي تم تمريرها (وهذا يتعارض قليلاً مع فلسفة اللغات الوظيفية ولكن f# شيء أكثر من ذلك).خذ بعين الاعتبار ما يلي:let myfunc (x: int byref) = x <- x + 10
هذا غريب.وأنا أعلم أنه إذا كان لديك مرجع
let myref = ref 10
ثم قم بذلك لتحرير القيمة:myref <- 10
ينشأ خطأ لأنه يجب أن يكون مثل هذا:myref := 10
.ومع ذلك، فإن حقيقة أنه في تلك الوظيفة يمكنني تحريرهاx
باستخدام<-
المشغل يعني ذلكx
ليس مرجعا، أليس كذلك؟إذا افترضت ذلك
x
ليس مرجعًا، فأنا أفترض أيضًا أنه في الوظائف عند الاستخدامbyref
على المعلمة، يمكن أن يتم تطبيق بناء الجملة القابل للتغيير على تلك المعلمة.لذا فهي مجرد مسألة بناء جملة، إذا افترضت ذلك فأنا موافق، وفي الواقع، كل شيء يعمل (لا توجد أخطاء في المترجم).ومع ذلك، ما هوx
?وظائف الاتصال:كيف يمكنني استخدام وظيفة باستخدام معلمات byref؟
ال
&
المشغل متورط ولكن هل يمكنك شرح ذلك بشكل أفضل من فضلك؟في هذه المقالة: معلمات ووسائط MSDN يتم توفير المثال التالي:type Incrementor(z) = member this.Increment(i : int byref) = i <- i + z let incrementor = new Incrementor(1) let mutable x = 10 // A: Not recommended: Does not actually increment the variable. (Me: why?) incrementor.Increment(ref x) // Prints 10. printfn "%d" x let mutable y = 10 incrementor.Increment(&y) (* Me: & what does it return? *) // Prints 11. printfn "%d" y let refInt = ref 10 incrementor.Increment(refInt) (* Why does it not work in A, but here it does? *) // Prints 11. printfn "%d" !refInt
المحلول
المرجع الكلمة الأساسية نعم عندما تكتب let a = ref 10
أنت تكتب بشكل أساسي let a = new Ref<int>(10)
أين ال Ref<T>
النوع يحتوي على حقل قابل للتغيير Value
.
قيمة الوصول ال :=
و !
العوامل هي مجرد اختصارات للكتابة:
a.Value <- 10 // same as writing: a := 10
a.Value // same as writing: !a
بواسطةالمرجع هو نوع خاص يمكن استخدامه (بشكل معقول) فقط في معلمات الطريقة.وهذا يعني أن الوسيطة يجب أن تكون في الأساس مؤشرًا لبعض مواقع الذاكرة (المخصصة على الكومة أو المكدس).إنه يتوافق مع out
و ref
المعدلات في C#.لاحظ أنه لا يمكنك إنشاء متغير محلي من هذا النوع.
& المشغل هي طريقة لإنشاء قيمة (مؤشر) يمكن تمريرها كوسيطة إلى دالة/طريقة تتوقع byref
يكتب.
وظائف الاتصال المثال مع byref
يعمل لأنك تقوم بتمرير الطريقة مرجعًا إلى متغير محلي قابل للتغيير.من خلال المرجع، يمكن للطريقة تغيير القيمة المخزنة في هذا المتغير.
ما يلي لا يعمل:
let a = 10 // Note: You don't even need 'mutable' here
bar.Increment(ref a)
والسبب هو أنك تقوم بإنشاء مثيل جديد لـ Ref<int>
وأنت تقوم بنسخ قيمة a
في هذه الحالة.ال Increment
تقوم الطريقة بعد ذلك بتعديل القيمة المخزنة على الكومة في مثيل Ref<int>
, ، لكن لم تعد لديك إشارة إلى هذا الكائن بعد الآن.
let a = ref 10
bar.Increment(a)
هذا يعمل، لأن a
هي قيمة النوع Ref<int>
وتقوم بتمرير مؤشر إلى المثيل المخصص للكومة Increment
ثم احصل على القيمة من الخلية المرجعية المخصصة للكومة باستخدام !a
.
(يمكنك استخدام القيم التي تم إنشاؤها باستخدام ref
كحجج ل byref
نظرًا لأن المترجم يتعامل مع هذه الحالة بشكل خاص - فسوف يشير تلقائيًا إلى ملف Value
الحقل لأن هذا سيناريو مفيد...).