الحصول على مجموعة مطبوعة من اتحاد تمييز لأنواع مختلفة من المصفوفات في F#
-
20-09-2019 - |
سؤال
إذا كان لدي اتحاد تمييز لأنواع مختلفة من المصفوفات ، فكيف يمكنني تحويلها إلى أنواعها "الفعلية"؟
type ItemStuff =
| Colors of string[]
| Sizes of int[]
let foo = Sizes [|1;2;3|]
بعد تشغيل ما سبق عندما أحصل على قيمة فو أراه:
val foo : ItemStuff = Sizes [|1;2;3|]
كيف يمكنني الحصول على مجموعة فعلية من INT من فو؟ هل أفتقد بعض بناء الجملة الذي يسمح لي بالوصول إلى شيء مثلfoo.[2]
؟ لا يمكنني التعداد من خلال فو ، لذلك لم أتمكن من استخدام الخريطة. يمكنني أن أكتب عضوًا لـ Itemstuff الذي يعيد صفيفًا مكتوبًا بشكل صحيح لكل نوع مختلف من الصفيف الذي أعود إليه ، لكن هذا لم يكن صحيحًا؟
ما هي أفضل مقارباتي هنا؟
هذا ما انتهى بي الأمر. أي أفكار حول طرق أفضل للقيام بذلك؟
type ItemProp =
| Colors of string[]
| Sizes of int[]
| Quants of int[]
member this.GetColors() =
match this with
| Colors (stringArray) ->
stringArray
| _ -> null
member this.GetIntArr() =
match this with
| Sizes (intArray) | Quants (intArray) ->
intArray
|_ -> null
foo.GetIntArr()
المحلول
كيف يمكنني الحصول على مجموعة فعلية من INT من فو؟
هذه هي المشكلة الفعلية منذ ذلك الحين foo
يقال فقط أن يكون له نوع ItemStuff
. لذلك لا يجب أن تحتوي على أ Sizes
-قيمة على الإطلاق - يمكن أن يكون Colors
أيضًا.
ومن هنا يجب أن يقرر البرنامج هنا
let getIntArray = function
| Sizes arr -> arr
| Colors _ -> failwith "Given value doesn't contain an int array`
getIntArray foo
سيعمل بشكل صحيح ولكن getIntArray (Colors [||])
سوف تفشل ، ولكن من نوع النوع كلاهما صالح.
لاحظ أنه إذا كنت متأكدًا تمامًا من أن العملية ستنجح ، فيمكنك استخدام مطابقة الأنماط مباشرة:
let getIntArray (Sizes arr) = arr
نصائح أخرى
عادةً ما تستخدم مطابقة الأنماط لأنك لن تعرف ما إذا كان ItemStuff
يحمل الألوان أو الأحجام. إذا كنت تعرف بالتأكيد أن لديك Sizes
على سبيل المثال ، يمكنك أن تفعل شيئًا مثل:
let (Sizes arr) = foo
لسحب الصفيف للخارج.
إذا كنت لا تمثل بالفعل إما/أو سيناريو (الألوان أو الأحجام) ، ففكر في استخدام أ نوع السجل هنا:
type ItemStuff =
{ Colors : string[];
Sizes : int[] } with
static member Default = { Colors = [||]; Sizes = [||] }
let foo = { ItemStuff.Default with Sizes = [|1;2;3|] }
printfn "%A" foo.Colors // [||]
printfn "%A" foo.Sizes // [|1; 2; 3|]
printfn "%d" foo.Sizes.[2] // 3
يمكنك أيضًا إرجاع نوع الخيار بدون أي شيء إذا لم يكن الاتحاد التمييز أ Sizes
.
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
ولكن ضع في اعتبارك أنه في النهاية في F# ، تقوم دالة بتحويل نوع بيانات الإدخال دائمًا إلى نوع بيانات الإخراج ، أو أن وظيفة تجعل فقط تأثيرًا جانبيًا (طباعة شيء على الشاشة أو إدخال البيانات في صفيف).
لذلك ، على سبيل المثال ، إذا كنت تريد فقط طباعة Sizes
(أو لا شيء إذا كان Colors
) سيكون أقصر كتابة وظيفة جديدة لهذا الغرض:
let printSizes item =
match item with
| Sizes(i) -> printfn "%A" i
| _ -> ()
بدلاً من:
let getIntArray item =
match item with
| Sizes(i) -> Some(i)
| _ -> None
let res = getIntArray foo
(function | Some(i) -> printfn "%A" i | _ -> ()) res