代码之家  ›  专栏  ›  技术社区  ›  mac10688

针对printformat编写单元测试

f#
  •  0
  • mac10688  · 技术社区  · 4 年前

      type ValueFormat<'p,'st,'rd,'rl,'t,'a> = {
          format: PrintfFormat<'p,'st,'rd,'rl,'t>
          paramNames: (string list) option
          handler: 't -> 'a
        }
        with 
          static member inline construct (this: ValueFormat<_,_,_,_,_,_>) =
            let parser s = 
              s |> tryKsscanf this.format this.handler
                |> function Ok x -> Some x | _ -> None
            let defaultNames =
                this.format.GetFormatterNames() 
                  |> List.map (String.replace ' ' '_' >> String.toUpperInvariant)
                  |> List.map (sprintf "%s_VALUE")
            let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>")
            let formatTokens = this.format.PrettyTokenize names
            (parser, formatTokens)
    

    我有信心我能把所有的事情都弄清楚,但是printformat把所有的泛型都扔给了我。

    我正在查找要进行单元测试的代码的文件是 here for the FSharp.Commandline framework .

    我的问题是,什么是printformat,应该如何使用它?

    printf.fs文件的链接是 here

    0 回复  |  直到 4 年前
        1
  •  1
  •   Tomas Petricek    4 年前

    这个 PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> defined in the F# source code ,有四个类型参数:

    • 'Result string 对于 sprintf

    • 'Printer "%d and %s" 会给你一个函数类型 int -> string -> 'Result

    • 'Tuple 是基于格式字符串生成的元组类型,例如。 “%d和%s” 会给你一个元组类型 int * string

    • 'State 'Residue 是在使用自定义格式化程序时使用的类型参数 %a ,但为了简单起见,我暂时忽略了这一点(除非您已经做了,否则永远不需要它) %a 格式(字符串)

    有两种使用类型的方法。或者是格式化,在这种情况下,您需要编写一个返回 '打印机 结果是。最困难的是,您需要使用反射构造返回函数。以下示例仅适用于一个格式字符串:

    open Microsoft.FSharp.Reflection
    
    let myformat (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Printer = 
      unbox <| FSharpValue.MakeFunction(typeof<'Printer>, fun o ->
        box (o.ToString()) )
      
    myformat "%d" 1
    myformat "%s" "Yo"
    

    这只是返回作为值传递给的参数 %d %s . 要使它适用于多个参数,您需要递归地构造函数(这样它就不仅仅是。 int -> string 而且 int -> (int -> string)

    在另一种用法中,定义一个返回 它需要根据指定的格式化字符串创建一个包含值的元组。这是一个只处理 %s码 %d级

    open FSharp.Reflection
    
    let myscan (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Tuple = 
      let args = 
        fmt.Value 
        |> Seq.pairwise
        |> Seq.choose (function
          | '%', 'd' -> Some(box 123)
          | '%', 's' -> Some(box "yo")
          | _ -> None)
      unbox <| FSharpValue.MakeTuple(Seq.toArray args, typeof<'Tuple>)
      
    myscan "%d %s %d"