إذا كان C # لديه مفهوم null لأنواع المرجع و Nullabe للهياكل. قد يستغرق هذا أحد النماذج التالية (للتوضيح ، يمكنني استخدام int int هنا ، لكن النوع يمكن أن يكون أي بنية).
- قيم الفارغة
- كثافة العمليات؟
تنصل Nullabe Nullable<T> , - ,
كلاهما يعادل.
توفر الفئة Nullable العديد من خصائص المساعدة والأساليب التي تجعل العمل أسهل مع أنواع البنيات الخالية. هذه هي التالية:
- HasValue
- قيمة
- GetValueOrDefault ()
- GetValueOrDefault (T)
هناك شيء مختلف قليلاً عن F # في شكل نوع
Option ، وهو نوع أكثر ملاءمة لـ F # يفضل عدم التعامل مع قيمة خالية ، لكن يفضل التعامل مع الأشياء من حيث "قد تحتوي على قيمة نوع" أو "قد لا يكون لديك القيمة. " هذا يبدو وكأنه Nullable ، لكن في النهاية هو نوع F # ، لذلك يمكنك توقع استخدامه بشكل طبيعي في أشياء F #.
شيء آخر جدير بالذكر مع نوع الخيار F # هو أنه يمكن استخدامه لأي نوع ، وليس فقط الهياكل. هذا يختلف عن .NET Nullable ، والذي لا يمكن استخدامه إلا مع الهياكل.
يتم استخدام القيمة بلا عندما لا توجد قيمة ؛ خلاف ذلك ، فإن تعبير
Some (...) يعين قيمة. يمكن استخدام القيمتين "لا شيء" و "لا شيء" عند التطابق مع نموذج ، مثال على ذلك سنراه في هذا المنشور.
مثل Nullable ، يحتوي نوع F # Option على العديد من الخصائص / الأساليب المساعدة ، والتي تظهر في الجدول أدناه.
لا شيءتي الخيارخاصية ثابتة تسمح لك بإنشاء قيمة معلمة بالقيمة بلا.
IsNoneمنطقيإرجاع صحيح إذا كانت المعلمة بلا.
IsSomeمنطقيإرجاع صحيح إذا كانت المعلمة لها قيمة غير None.
بعض
تي الخيارعضو ثابت يقوم بإنشاء معامل لا تكون قيمته بلا.
قيمة'T
إرجاع قيمة أساسية أو طرح NullReferenceException إذا كانت القيمة بلا.
خلق خيارات
الآن ، بعد أن عرفنا أنواع الخيارات ، كيف نقوم بإنشائها. لنلقي نظرة على بعض الأمثلة. لاحظ أنه في هذا المثال ، استخدمت الطرق المساعدة IsSome / IsNone. شخصياً ، أعتقد أن المقارنة مع عينة هي أفضل طريقة ، حيث ستساعدك على مقارنة جميع الحالات ، بما في ذلك خيار "لا".
في الحقيقة ، سأوضح لك مدى سهولة حدوث خطأ ما عند التعامل مع أنواع Option إذا قررت استخدام أساليب المساعد ، لكن أولاً دعونا نلقي نظرة على مثال للحالة المناسبة.
let someInt = Some(43) let someString = Some("cat") let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let someInt = Some(43)" printfn "let someString = Some(\"cat\")" printfn "printTheOption (someInt)" printTheOption someInt printfn "printTheOption (someString)" printTheOption someString

ولكن ماذا لو حاولنا مرة أخرى باستخدام هذا الرمز ، حيث لا يوجد لدينا قيمة Option ، والتي سننتقل إلى وظيفة printTheOption:
let demoNone = None let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let demoNone = None" printfn "printTheOption demoNone" printTheOption demoNone

كما ترون ، لدينا مشكلة هنا. المشكلة هي أننا حاولنا الحصول على قيمة Option باستخدام الخاصية المساعدة Option.Value ، وفي هذه الحالة ، لا شيء ، لذلك حصلنا على NullReferenceException. يظهر في الجدول أعلاه أنه عند استخدام الخصائص والأساليب المساعدة ، يمكنك الحصول على استثناء. حسنًا ، يمكنك استخدام طريقة IsNone وستقوم دائمًا بالتحقق من القيمة باستخدام هذا عندما يمكنك فقط استخدام تطابق نقش جميل.
إذا لم تتمكن من قبول ذلك ، اسأل نفسك عدد المرات التي كان عليك فيها التحقق من القيمة الخالية عند استخدام C #. وقد أدى ذلك أيضًا إلى تضمين الأشخاص تصميمات وظيفية ، مثل Maybe Null Monad ، في رمز .NET عادي.
والآن ، بعد أن رأينا خطر استخدام الأساليب / الخصائص المساعدة ، دعونا نحول انتباهنا الآن إلى الطريقة التي يمكننا بها تجنب هذه الاستثناءات:
et printTheOption (opt :Option<'a>) = match opt with | Some a -> printfn "opt is Some, and has value %A" a | None -> printfn "opt is None" let demoNone = None let someInt = Some 1 let someString = Some "crazy dude in the monkey house" printTheOption demoNone printTheOption someInt printTheOption someString
رأيي الشخصي هو أنه أكثر قابلية للقراءة من التعليمات البرمجية التي تنتشر مع IsSome / IsNone في كل مكان. هذا ، بطبيعة الحال ، من أعمال الجميع ، ولكن حقيقة أننا قمنا بتغطية جميع الأساسيات هنا في هذه الوظيفة البسيطة لا يمكن تجاهلها.

الخيار مقابل Null
لذلك ، تحدثنا عن Option in F # مقارنةً بـ Nullabe ، ونعلم أن نوع Option يمكن استخدامه مع أي نوع ، في حين لا يمكن استخدام Nullable إلا في الهياكل. ولكن ماذا عن أنواع الخيارات مقارنة بأنواع المراجع العادية في .NET. حسنًا ، هناك فوز كبير لـ Option هو أنه عند استخدام نوع المرجع في .NET ، فأنت تتعامل مع مرجع مؤشر ، والذي يمكن تعيينه على هذا النحو. ومع ذلك ، يظل نوع الكائن كما هو معلن ، والذي قد يحتوي على مرجع صالح للكائن في الكومة (Heap) أو قد يكون فارغًا.
سيكون من الطبيعي أن تكتب مثل هذا:
string s1 = "cats"; int s1Length = s1.Length; string s2 = null; int s2Length = s2.Length;
سيتم تجميع هذا بنجاح. ومع ذلك ، عندما نقوم بتشغيل هذا ، سوف نحصل على NullReferenceException ، والذي سنضطر إلى الخروج لحماية جميع التعليمات البرمجية من التواجد المحتمل خالية. يصبح هذا مملاً بسرعة كبيرة ، حتى لو كان لديك فئة حماية صغيرة لطيفة ستقوم بالتحقق من القيمة والتعامل معها / إلقاء استثناء ذي مغزى أكبر.
تستخدم لقطة الشاشة هذه LinqPad ، لذلك قد يبدو الأمر غير عادي إلى حد ما إذا لم تكن قد شاهدت LinqPad من قبل ، ولكن صدقوني ، فستظل تحصل على نفس النتيجة في IDE مختلف.

الآن دعونا نرى كيف سيبدو الرمز المكافئ في F #
let s1 = "Cats" let s1Length = s1.Length; let s2 = None let s2Length = s2.Length; //excplicily string typed None let s3 = Option.None let s3Length = s3.Length;
في هذا الرمز ، سوف تحصل على خطأ فوري في الترجمة ، حيث سيتم اعتبار s3 نوعًا آخر لا يحتوي على خاصية "الطول".
مقارنة الخيار
تعتبر أنواع الخيارات متساوية ، وهي من نفس النوع ، وأن الأنواع التي تحتويها متساوية ، والتي تلتزم بقواعد المساواة من النوع المحتجز.
لذلك هذا النوع من الأشياء يمكن أن يؤدي إلى خطأ فوري في وقت الترجمة في F #
let o1 = Some 1 let o2 = Some "Cats" printfn "o1=o2 : %b" (o1 = o2)

هذا سوف يعمل كما هو متوقع لأن الأنواع هي نفسها
let o1 = Some "Cats" let o2 = Some "Cats" let o3 = Some "cats" printfn "o1=o2 : %b" (o1 = o2) printfn "o2=o3 : %b" (o2 = o3)
