我想定义一个类型:
type blah =
AThing
| AnotherThing
with
static member ofString : string -> blah
override x.ToString () : string
我想确保这两种方法始终保证一致。这样做的一个好方法是从同一个对列表中构造两个映射,然后将它们转换为两个方法的明显实现。大致是:
let pairs = [Athing, "AThing"; AnotherThing, "AnotherThing"]
let tostr = Map.ofList pairs
let toblah = pairs |> List.map swap |> Map.ofList
我认为这段代码只能在静态成员函数中定义。需要可以从ofString访问静态位,这是静态的。它不能在类型之前定义,因为列表依赖于它。之后无法定义,因为F#不允许稍后声明和实现方法(以与C ++相同的方式)。这样就可以在静态成员和静态成员之间进行选择。编译器说扩充中不允许使用static let。 (?)
当放入静态成员函数时,代码工作正常,但是每次需要它时都会生成映射。不用说,这甚至比线性搜索效率更低。我该怎么做呢?非常感谢。
答案 0 :(得分:3)
编译(带警告)
type blah =
AThing
| AnotherThing
let pairs = [AThing, "AThing"; AnotherThing, "AnotherThing"]
let tostr = Map.ofList pairs
let toblah = pairs |> List.map (fun (x,y)->y,x) |> Map.ofList
type blah
with
static member ofString s = toblah.[s]
override x.ToString () = tostr.[x]
并演示扩充(定义类型,执行其他代码,然后执行type blah with
以定义更多成员)。
答案 1 :(得分:2)
我不明白你的观点。出了什么问题:
type blah =
| AThing
| AnotherThing
with
static member ofString = function
| "AThing" -> AThing
| "AnotherThing" -> AnotherThing
| _ -> failwith "Unwellformed string"
override x.ToString () =
match x with
| AThing -> "AThing"
| AnotherThing -> "AnotherThing"
模式匹配是Θ(1),它在F#中非常有效。
答案 2 :(得分:2)
我相信你正在努力做到以下几点:因为任何被歧视的联盟都有能力从特定的DU情况转变为其名称并且没有负担硬编码每对的关系,这两个答案都由Brian和垫。
如果牺牲ToString()的覆盖来代替等效的静态成员,可以使用以下方法完成:
open Microsoft.FSharp.Reflection
type Blah =
| AThing
| AnotherThing
[<AutoOpenAttribute>]
module BlahExt =
let cases = FSharpType.GetUnionCases typeof<Blah>
let toBlah = dict [for case in cases do yield (case.Name, FSharpValue.MakeUnion(case, [||]) :?> Blah)]
let fromBlah = dict [for case in cases do yield ((FSharpValue.MakeUnion(case, [||]) :?> Blah), case.Name)]
type Blah
with
static member ofString name =
if toBlah.ContainsKey name then (toBlah.Item name) else failwith "bad string"
static member toString x = fromBlah.Item x
现在printfn "ofString: %A" (Blah.ofString "AThing")
显示工会案例AThing
,反之亦然printfn "toString: %s" (Blah.toString AThing)
显示字符串AThing
。
您可以注意到我没有列出您的DU的成员,这通过反射实现,并保证自动正确映射。对于任意数量的单位情况,这种方法 - 两两百个 - 无需对特定情况进行硬编码。
答案 3 :(得分:2)
以下是根据需要运行的代码:
type blahFactory() =
static let pairs = printf "array initialized; "; [AThing, "AThing"; AnotherThing, "AnotherThing"]
static member tostr = Map.ofList pairs
static member toblah = pairs |> List.map swap |> Map.ofList
and blah =
| AThing
| AnotherThing
with
static member ofString (string) = blahFactory.toblah.[string]
override x.ToString () = blahFactory.tostr.[x]
我已经放置printf
指令来演示数组只被初始化一次。
您可能认为有用的几点想法
首先,使用DU是提供样本的开销。如果您的数据很简单,您可以考虑使用enum
类型
如果你真的是指DU,这可能是未来可能出现问题的迹象。考虑一下:
type blah =
| AThing of string
| AnotherThing of int * int
在这种情况下,构造和比较都是不可能的。
您有任何理由不使用标准XML序列化吗?