F# collection initializer syntax

后端 未结 6 561
猫巷女王i
猫巷女王i 2021-02-03 19:05

What is the collection initializer syntax in F#? In C# you can write something like:

new Dictionary() {
    {\"One\", 1},
    {\"two\", 2}}


        
相关标签:
6条回答
  • 2021-02-03 19:20

    As Jared says, there is no built-in support for this for arbitrary collections. However, the C# code is just syntactic sugar for Add method calls, so you could translate it to:

    let coll = MyCollectionType()
    ["One", 1; "Two", 2] |> Seq.iter coll.Add
    

    If you want to get fancy, you could create an inline definition to streamline this even further:

    let inline initCollection s =
      let coll = new ^t()
      Seq.iter (fun (k,v) -> (^t : (member Add : 'a * 'b -> unit) coll, k, v)) s
      coll
    
    let d:System.Collections.Generic.Dictionary<_,_> = initCollection ["One",1; "Two",2]
    
    0 讨论(0)
  • 2021-02-03 19:33

    You can use the same :

    open System.Collections.Generic
    
    Dictionary<int, string>(dict [ (1, "a"); (2, "b"); (3, "c") ])
    

    Cheers.

    0 讨论(0)
  • 2021-02-03 19:34

    I don't believe F# has an explicit collection initializer syntax. However it's usually very easy to initialize F# collections. For example

    let map = [ ("One", 1); ("Two", 2) ] |> Map.ofSeq
    

    Getting to BCL collections is usually a bit more difficult because they don't always have the handy conversion functions. Dictionary<TKey, TValue> works though because you can use the LINQ method

    let map = 
      let list = [ ("One", 1); ("Two", 2) ] 
      System.Linq.Enumerable.ToDictionary(list, fst, snd)
    
    0 讨论(0)
  • 2021-02-03 19:35

    The lack of a collection initializer is annoying for some XAML-centric APIs like Workflow 4.0 which rely on collection initializers instead of ctors, e.g.

    new Sequence { Activities = { WriteLine { Text = "In the sequence!" } } };
    

    In such cases, imperative .Add() is awkward because the value is conceptually declarative even though it's technically mutable/imperative. However, there's no common base class for the set of all activities which declare an Activities child: the "Activities" member is a pattern and not an interface, so you can't just write a normal helper function which adds children to any activity. Fortunately, F# member constraints come to the rescue.

    In order to write this:

    Sequence() |> add [Sequence(DisplayName="InnerSeq"); WriteLine(Text = InArgument<_>("In the sequence!"))]
    

    You first need to define an inline helper function called "add":

    let inline add (children: Activity seq) =
        let inline doAdd (activity: ^Activity) : ^Activity when ^Activity : (member get_Activities : unit -> Activity Collection) =
            let collection = (^Activity : (member get_Activities : unit -> Activity Collection) (activity))
            for child in children do
                collection.Add(child)
            activity
        doAdd
    

    This still isn't quite as nice as the C# syntax but at least it's still declarative. IMHO this is not so much as a fault with F# as with collection-initializer-centric APIs, but at least F# allows a workaround.

    0 讨论(0)
  • 2021-02-03 19:36

    Given that the C# collection initializer syntax is syntactic sugar for calling .Add and that implies a mutable collection - I'm not sure you'll see any such syntax in F#. It's initialize all in one go as per JaredPar's answer, or do it manually.

    0 讨论(0)
  • 2021-02-03 19:39

    To elaborate a bit on collection initialization in F#, here are a few examples:

    read-only dictionary

    dict [ (1, "a"); (2, "b"); (3, "c") ]
    

    seq (IEnumerable<T>)

    seq { 0 .. 99 }
    

    list

    [1; 2; 3; 4; 5]
    

    set

    set [1; 2; 3; 4; 5]
    

    array

    [| 1; 2; 3; 4; 5 |]
    
    0 讨论(0)
提交回复
热议问题