كيف تعلن أن قيم إدخال القاموس قابلة للتغيير؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

يقدم Google الكثير من الأمثلة لإضافة وحذف الإدخالات في قاموس F# (أو مجموعة أخرى).لكني لا أرى أمثلة تعادل

myDict["Key"] = MyValue;

لقد حاولت

myDict.["Key"] <- MyValue

لقد حاولت أيضًا إعلان القاموس باسم

Dictionary<string, mutable string>

وكذلك العديد من المتغيرات في هذا الشأن.لكني لم أتوصل إلى التركيبة الصحيحة بعد..لو أنه يكون ممكن فعلا في F#.

يحرر:الكود المخالف هو :

type Config(?fileName : string) =
    let fileName = defaultArg fileName @"C:\path\myConfigs.ini"

    static let settings =
        dict[ "Setting1", "1";
              "Setting2", "2";
              "Debug",    "0";
              "State",    "Disarray";]

    let settingRegex = new Regex(@"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))")

    do  File.ReadAllLines(fileName)
        |> Seq.map(fun line -> settingRegex.Match(line))
        |> Seq.filter(fun mtch -> mtch.Success)
        |> Seq.iter(fun mtch -> settings.[mtch.Groups.Item("key").Value] <- mtch.Groups.Item("value").Value)

الخطأ الذي أتلقاه هو:

System.NotSupportedException: This value may not be mutated
   at Microsoft.FSharp.Core.ExtraTopLevelOperators.dict@37-2.set_Item(K key, V value)
   at <StartupCode$FSI_0036>.$FSI_0036_Config.$ctor@25-6.Invoke(Match mtch)
   at Microsoft.FSharp.Collections.SeqModule.iter[T](FastFunc`2 action, IEnumerable`1 sequence)
   at FSI_0036.Utilities.Config..ctor(Option`1 fileName)
   at <StartupCode$FSI_0041>.$FSI_0041.main@()
stopped due to error
هل كانت مفيدة؟

المحلول

و # اثنين من هياكل البيانات النقابي المشتركة:

وواحد كنت الأكثر استخداما ل، وقاموس قابلة للتغيير الذي يرث هذا لانها وجودها في BCL ويستخدم جدول هاش تحت غطاء محرك السيارة.

let dict = new System.Collections.Generic.Dictionary<string,int>()
dict.["everything"] <- 42

وكما هو معروف <لأ href = "http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/fsharp.core/microsoft.fsharp.collections.map.html الآخر "يختلط =" noreferrer "> خريطة و هو في نمط وظيفي مشترك، غير قابل للتغيير وتنفيذها مع شجرة ثنائية.

وبدلا من العمليات التي من شأنها تغيير قاموس، توفر خرائط العمليات التي يعود خريطة جديدة والتي هي نتيجة من أي تغيير المطلوب. في كثير من الحالات، تحت غطاء محرك السيارة ليست هناك حاجة لتقديم نسخة جديدة تماما من الخريطة بأكملها، حتى تلك الأجزاء التي يمكن أن تكون مشتركة عادة هم. على سبيل المثال:

let withDouglasAdams = Map.add "everything" 42 Map.empty

وسيبقى إلى الأبد withDouglasAdams قيمة كجمعية من "كل شيء" إلى 42. حتى إذا كنت تفعل في وقت لاحق:

let soLong = Map.remove "everything" withDouglasAdams

وثم تأثير هذا 'إزالة' مرئيا فقط عن طريق قيمة soLong.

خريطة F # الصورة هو، كما ذكرنا، كما نفذت شجرة ثنائية. وبالتالي البحث هو O (سجل ن) في حين أن (حسن تصرف) القاموس يجب أن يكون O (1). في الممارسة العملية قاموس أساس التجزئة سوف تميل إلى التفوق على واحد شجرة مقرها في جميع بسيطة تقريبا (عدد قليل من العناصر، احتمال ضعيف الاصطدام) على هذا النحو يشيع استخدامها. وقال أن الجانب غير قابل للتغيير خارطة قد تسمح لك لاستخدامه في الحالات التي يكون فيها القاموس سيفضلون في هذه الحالة يتطلب تأمين أكثر تعقيدا أو لإرسال مزيد من رموز 'الأنيق' مع آثار جانبية أقل، وبالتالي يبقى بديلا مفيدا.

وهذه ليست إلا أن مصدر المشكلة. في "المشغل" ديكت إرجاع تنفيذ صراحة غير قابل للتغيير IDictionary<K,T> (على الرغم من عدم تشير هذه الوثائق في انها).

من ، fslib خارج pervasives.fs (لاحظ أيضا استخدام الخيارات على مفاتيح):

let dict l = 
    // Use a dictionary (this requires hashing and equality on the key type)
    // Wrap keys in an Some(_) option in case they are null 
    // (when System.Collections.Generic.Dictionary fails). Sad but true.
    let t = new Dictionary<Option<_>,_>(HashIdentity.Structural)
    for (k,v) in l do 
        t.[Some(k)] <- v
    let d = (t :> IDictionary<_,_>)
    let c = (t :> ICollection<_>)
    let ieg = (t :> IEnumerable<_>)
    let ie = (t :> System.Collections.IEnumerable)
    // Give a read-only view of the dictionary
    { new IDictionary<'key, 'a> with 
            member s.Item 
                with get x = d.[Some(x)]            
                and  set (x,v) = raise (NotSupportedException(
                                            "This value may not be mutated"))
   ...

نصائح أخرى

ما الخطأ الذي تحصل عليه؟لقد جربت ما يلي وهو يجمع جيدًا

let map = new System.Collections.Generic.Dictionary<string,int>()
map.["foo"] <- 42

يحرر تحقق من أن هذا الرمز يعمل بشكل جيد أيضًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top