问题
I am trying to create a record which uses one of the previously defined fields to calculate the value of another, within the same constructor. e.g.
myRecordType = {Foo:int; Bar:int[]}
myRecord = {Foo = 5;
Bar = Array.init Foo (fun i -> i)}
When I try this it doesn't recognise Foo as already existing. I also can't reference Foo using myRecord.Foo, but that makes sense since myRecord hasn't been constructed yet. However I would've thought that Foo and Bar would be in the same scope, so Bar could access Foo, but apparently not.
The size of the Bar array depends on the value of Foo, so how is it possible to set up a record of this format?
回答1:
You cannot reference other fields, you shouldn't even take for granted the order of fields evaluation.
You can do it by additional let binding:
let myrecord =
let calcedFoo = 5
{ Foo = calcedFoo; Bar = Array.init calcedFoo id }
You can think of record construction expression as a function where right sides of assignments are parameters passed to that function.
回答2:
I would go with what @Bartek suggests and use local let binding to store all pre-computed values that you need to have before you can create the record.
That said (depending on your domain), you might also be able to change the structure of your record, so that you have one record with all the primary values and another record that contains the primary one and adds all secondary values:
type MyRecordPrimary = { Foo:int }
type MyRecord = { Primary:MyRecordPrimary; Bar:int[] }
let myPrim = { Foo = 5 }
let myRec = { Primary = myPrim; Bar = Array.init myPrim.Foo (fun i -> i)}
Doing this just to make the construction a bit shorter would be silly, but if the primary record actually represents something in your domain, then this might be a good alternative.
来源:https://stackoverflow.com/questions/32406610/reference-a-record-from-within-itself-during-construction