如何编写带有可变数量参数的F#printfn的自定义版本?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何编写带有可变数量参数的F#printfn的自定义版本?相关的知识,希望对你有一定的参考价值。

我想写一个F#printfn函数的扩展版本,除了文本之外还打印当前时间。像这样的东西:

let printimefn fmt =
    let time = DateTime.Now
    let strtime = sprintf "%02d:%02d:%02d" time.Hour time.Minute time.Second
    printfn "%s %A"  strtime fmt

不幸的是,这不能按预期工作。 “fmt”参数失去其类型Printf.TextWriterFormat <'T>。

我可以通过使用类型注释来强制它的类型:

let printimefn (fmt : Printf.TextWriterFormat<'T>) =
    let time = DateTime.Now
    let strtime = sprintf "%02d:%02d:%02d" time.Hour time.Minute time.Second
    printfn "%s %A"  strtime fmt

但是后来printimefn的结果变成了单位,而不是'T.所以它仍然无效。我想知道编写自定义printfn函数的正确方法是什么。

答案

这可以用Printf.ksprintf完成

let printimefn fmt =
    let time = DateTime.Now
    Printf.ksprintf (
        fun s ->
            printfn "%02d:%02d:%02d %s" time.Hour time.Minute time.Second s)
        fmt
另一答案

我想通过移动函数的时间读出来证明这一点,原因有两个。主要是为了演示如何添加一个或多个不被ksprintf消耗的参数,还因为我们应该有一个没有副作用的函数。如果您希望在函数内部读取时间,则创建一个读取时间的包装函数,然后调用以下函数。

首先,有两个未传递给ksprintf的显式参数。然后隐式地遵循格式字符串和格式字符串所需的任何隐式参数。

let tsprintf (dateTime: DateTime) (tag: string) =
    let dateTimeString =
        dateTime.ToString (@"yyyy/MM/dd HH:mm:ss",
            System.Globalization.CultureInfo.InvariantCulture)
    Printf.ksprintf (fun formatString ->
        "[" + dateTimeString + " <" + tag + ">] " + formatString)

let testTime = DateTime(1987, 12, 31, 11, 59, 58)

let message = tsprintf testTime "007" "Hello %s!" "James Bond"

message.Dump() // LINQPad output : [1987/12/31 11:59:58 <007>] Hello James Bond!

InvariantCulture与所选的时间格式字符串相结合,可以确保您看到的结果正是最后评论中的内容,无论在何处或什么。

我使用DateTime.ToString的原因是,无论您想要哪种方式,它都会格式化DateTime。在ksprintf中格式化它似乎不是一个好主意。

ksprintf未使用的参数在tsprintf中显式声明。 ksprintf的格式字符串和以下参数未明确声明,但它们遵循所有显式声明的参数。

以上是关于如何编写带有可变数量参数的F#printfn的自定义版本?的主要内容,如果未能解决你的问题,请参考以下文章

UDF:处理范围和可变数量的参数

在R中使用带有向量而不是可变数量的参数的sprintf

如何编写一个丢弃其参数的通用可变参数 lambda?

为具有可变数量参数的不同函数编写通用包装器

如何在 MySQL 存储过程中选择与可变数量参数匹配的值

构建字符串,这取决于可变数量的参数