简体   繁体   中英

Adding Dictionary Key to a constructor in F#

Being as how I am new to F#, this may seem like some kind of elementary question. But here goes. I have a class with a constructor using the following code:

new () = { 
    _index = 0; _inputString = ""; 
    _tokens = new Dictionary<string, string>() {
        {"key", "value"}
    }
}

Everything works except F# doesn't seem to allow me to add tokens to my dictionary. I can initialize it with a new Dictionary<> object, but if I try to populate, it throws an error. I also can't do it with the.Add member. I have seen examples of F# constructors initializing field values, but is there no way to execute other code maybe?

Because Dictionary has a constructor taking an IDictionary instance , you can use the built-in dict function to help you here:

open System.Collections.Generic

type Foo =
    val _index       : int
    val _inputString : string
    val _tokens      : Dictionary<string, string>
    new () =
        {
            _index = 0
            _inputString = ""
            _tokens = Dictionary(dict [("fooKey", "fooValue")])
        }

However, it's also possible to execute non-trivial code before or after your constructor's object initializer:

type Bar =
    val _index       : int
    val _inputString : string
    val _tokens      : Dictionary<string, string>
    new () =
        let tokens = Dictionary()
        tokens.Add ("barKey", "barValue")
        {
            _index = 0
            _inputString = ""
            _tokens = tokens
        }

type Baz =
    val _index       : int
    val _inputString : string
    val _tokens      : Dictionary<string, string>
    new () as this =
        {
            _index = 0
            _inputString = ""
            _tokens = Dictionary()
        } then
        this._tokens.Add ("bazKey", "bazValue")

Ildjarn already answered your question, but let me just add a note about coding style - I think that most of the F# programs these days prefer the implicit constructor syntax, where you define one implicit constructor as part of the type declaration. This usually makes code a lot simpler. You could write something like:

type Bah() = 
  let index = 0
  let inputString = ""
  let tokens = new Dictionary<string, string>()
  do tokens.Add("bazKey", "barValue")

  member x.Foo = "!"

This defines a parameter-less constructor and private fields (eg index ). In your sample, this doesn't make much sense (because all fields are immutable, so index will always be zero). I suppose you probably have other constructor, in which case you can write something like:

type Baf(index:int, inputString:string, tokens:Dictionary<string, string>) =
  new() = 
    let tokens = new Dictionary<string, string>()
    tokens.Add("bazKey", "barValue")
    Baf(0, "", tokens)

Here, you get two constructors - one parameter-less and one that takes three parameters. You can also make the implicit constructor private and expose only more specific cases:

type Baf private (index:int, inputString:string, tokens:Dictionary<string, string>) =
  // (...)

As a side-note, I also changed the naming from _index to index , because I don't think that F# guidelines recommend using underscores (although, it may make sense for fields declared using val )

In F#, everything is an expression, so you can initialize _tokens like so:

open System.Collections.Generic
type Foo =
    val _index       : int
    val _inputString : string
    val _tokens      : Dictionary<string, string>
    new () =
        {
            _index = 0
            _inputString = ""
            _tokens = 
                let _tokens = Dictionary() 
                _tokens.Add ("key", "value") 
                _tokens
        }

The light syntax can trick you into thinking that let bindings and sequential expressions are statements, but if we write out the full verbose syntax for those expressions it's clear:

...
_tokens = let _tokens = Dictionary() in _tokens.Add ("key", "value") ; _tokens
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM