最近一直在与很多TimeSpans合作,并且需要获得总和和平均值.
但是,TimeSpan既不定义运算符get_Zero也不定义DivideByInt,因此Seq.sum和Seq.average不能直接使用此类型.以下无法编译:
open System
type System.TimeSpan
with
static member Zero with get() = TimeSpan()
static member (/) (n:DateTime, d:int) = DateTime( n.Ticks / (int64) d )
let ts = [ TimeSpan(10L); TimeSpan(99L) ]
let sum = ts |> Seq.sum
let avg = ts |> Seq.average
Run Code Online (Sandbox Code Playgroud)
是否有一些F#魔术可以在现有类型上定义这些运算符?
我知道以下内容可行(并且应该更有效地启动),但我仍然对上面的内容感到好奇,所以我可以将它添加到我的工具箱中以便与其他类型一起使用.
let sum = TimeSpan( ts |> Seq.sumBy (fun t -> t.Ticks) )
let avg = TimeSpan( let len = ts |> Seq.length in sum.Ticks / int64 len )
Run Code Online (Sandbox Code Playgroud)
据我所知,静态成员约束(由函数使用Seq.sum)不能发现由类型扩展(实质上是扩展方法)添加的成员,所以我认为没有直接的方法来做到这一点.
我能想到的最好的选择是在System.TimeSpanstruct 周围创建一个简单的包装器.然后,您可以定义所有必需的成员.代码如下所示:
[<Struct>]
type TimeSpan(ts:System.TimeSpan) =
member x.TimeSpan = ts
new(ticks:int64) = TimeSpan(System.TimeSpan(ticks))
static member Zero = TimeSpan(System.TimeSpan.Zero)
static member (+) (a:TimeSpan, b:TimeSpan) =
TimeSpan(a.TimeSpan + b.TimeSpan)
static member DivideByInt (n:TimeSpan, d:int) =
TimeSpan(n.TimeSpan.Ticks / (int64 d))
let ts = [ TimeSpan(10L); TimeSpan(99L) ]
let sum = ts |> Seq.sum
let avg = ts |> Seq.average
Run Code Online (Sandbox Code Playgroud)
我调用了类型TimeSpan,因此它隐藏了标准System.TimeSpan类型.但是,ts.TimeSpan当您需要访问底层系统类型时,仍然需要编写,因此这不是很好.