我正在编写某种序列化库(用于学习F#)。现在我坚持这个:
假设我们已经有一些基本类型的序列化函数:
type StoreOps =
static member inline store(x:int) = ...
static member inline store(x:int64) = ...
static member inline store(x:float) = ...
static member inline store(x:float32) = ...
static member inline store(x:bool) = ...
static member inline store(x:string) = ...
....
现在我想实现泛型函数来存储任何基本类型数组:
let inline store(x:'T[]) =
x |> Array.iter StoreOps.store
,但编译器无法编译它(错误消息显示:A unique overload for method 'store' could not be determined based on type information prior to this program point
)。
在F#中实现此类功能的正确方法是什么?因为我不想为int[]
,bool[]
,float[]
复制粘贴N个相等的函数...
答案 0 :(得分:4)
首先,对于采用特定类型参数的定义,您可能不需要inline
。其次,简短的回答可能是“没有好办法”。但是,如果你愿意忍受可怕的黑客行为,你可以做类似的事情:
type StoreOps =
... // everything you've currently got
let inline storeArray< ^t, ^u when (^t or ^u) : (static member store : ^u -> unit)> arr =
arr
|> Array.iter (fun x -> ((^t or ^u) : (static member store : ^u -> unit) x))
type StoreOps with
static member inline store arr = storeArray<StoreOps,_> arr
如果您不希望公开storeArray
,也可以let inline private storeArray...
帮助私有(使用{{1}}。
答案 1 :(得分:3)
一种解决方法是将store
函数作为参数传递给泛型函数:
type StoreOps =
static member inline store (x: int) = ...
static member inline store (x: int64) = ...
static member inline store (x: float) = ...
static member inline store (x: float32) = ...
static member inline store (x: bool) = ...
static member inline store (x: string) = ...
static member storeArray xs f =
xs |> Array.iter f
....
// The compiler chooses the right overload based on types of array elements
StoreOps.storeArray [|100; 200|] StoreOps.store
StoreOps.storeArray [|100L; 200L|] StoreOps.store
答案 2 :(得分:2)
你可以这样做:
type StoreOps = StoreOps with
static member ($) (StoreOps,x:int) = (* code for storing *) ()
static member ($) (StoreOps,x:int64) = (* code for storing *) ()
static member ($) (StoreOps,x:float) = (* code for storing *) ()
static member ($) (StoreOps,x:float32) = (* code for storing *) ()
static member ($) (StoreOps,x:bool) = (* code for storing *) ()
static member ($) (StoreOps,x:string) = (* code for storing *) ()
let inline store(x:_[]) = Array.iter (fun a -> StoreOps $ a) x
它会自动为您生成约束。