问题
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