الحصول على مجموعة مطبوعة من اتحاد تمييز لأنواع مختلفة من المصفوفات في F#

StackOverflow https://stackoverflow.com/questions/1939113

  •  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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top