在F#中,你如何理解ParamArray函数(如sprintf)?

Fen*_*ndy 6 printf f# currying paramarray

在F#中,你如何理解接受可变数量参数的函数?

我有这样的代码...(日志功能只是一个例子,确切的实现并不重要)

let log (msg : string) =
    printfn "%s" msg

log "Sample"
Run Code Online (Sandbox Code Playgroud)

它使用sprintf格式化的字符串在整个代码中调用,例如.

log (sprintf "Test %s took %d seconds" "foo" 2.345)
Run Code Online (Sandbox Code Playgroud)

我想在日志函数中讨论sprintf功能,看起来像......

logger "Test %s took %d seconds" "foo" 2.345
Run Code Online (Sandbox Code Playgroud)

我尝试过类似的东西

let logger fmt ([<ParamArray>] args) =
    log (sprintf fmt args)
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何将ParamArray参数传递给sprintf调用.

这是如何在F#中完成的?

des*_*sco 7

let log (s : string) = ()
let logger fmt = Printf.kprintf log fmt

logger "%d %s" 10 "123"
logger "%d %s %b" 10 "123" true
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 6

printfF#中类似函数的行为在某种程度上是特殊的.它们采用格式字符串,指定预期参数是什么.您可以使用Printf.kprintfdesco所示来定义您自己的带有格式字符串的函数,但是您无法更改格式字符串的处理.

如果你想做一些像C#params(其中参数的数量是可变的,但不依赖于格式字符串),那么你可以ParamArray直接在一个成员上使用属性:

open System

type Foo = 
  static member Bar([<ParamArray>] arr:obj[]) =
    arr |> Seq.mapi (fun i v -> printfn "[%d]: %A" i v)
Run Code Online (Sandbox Code Playgroud)

然后你可以Foo.Bar使用任意数量的参数调用而不使用格式字符串:

Foo.Bar("hello", 1, 3.14)
Run Code Online (Sandbox Code Playgroud)

对于字符串格式化,这不太优雅,但在其他情况下可能很有用.不幸的是,它只适用于成员(而不是定义的功能let)