如何使用printf自定义自定义类型的输出?

fla*_*ine 30 printf f# string-formatting f#-interactive

我已经阅读了很多专家F#,正在构建一个实际的应用程序.在调试时,我已经习惯于传递这样的fsi命令,以使repl窗口中的内容清晰可见:

fsi.AddPrinter(fun (x : myType) -> myType.ToString())
Run Code Online (Sandbox Code Playgroud)

我想扩展它以使用printf格式化程序,所以我可以输入例如

printf "%A" instanceOfMyType 
Run Code Online (Sandbox Code Playgroud)

并控制自定义类型的输出.本书暗示可以做到这一点(第93页,"可以扩展通用结构格式以适用于任何用户定义的数据类型,F#网站上涵盖的主题"),但我没有找到任何关于如何实际上实现这一点.有谁知道怎么样?它甚至可能吗?

编辑:

我应该包含一个代码示例,它是我正在处理的记录类型,例如

type myType = 
    {a: int}        
    override m.ToString() = "hello"

let t = {a=5}
printfn "%A" t
printfn "%A" (box t)  
Run Code Online (Sandbox Code Playgroud)

两个印刷语句产生:

{a = 5;}
Run Code Online (Sandbox Code Playgroud)

Tod*_*wen 39

看起来在F#2.0中执行此操作的正确方法是使用StructuredFormatDisplay属性,例如:

[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,{a = 42;}你得到的不是默认值hello 42.

这对于对象,记录和联合类型的工作方式相同.虽然模式必须是格式"PreText {PropertyName} PostText"(PreTextPostText是可选的),但这实际上比ToString()因为:

  1. PropertyName可以是任何类型的财产.如果它不是字符串,那么它也将受到结构化格式的限制.Don Syme的博客给出了以这种方式递归格式化树的示例.

  2. 它可能是计算属性.所以你实际上可以ToString()为记录和联合类型工作,尽管它是以一种相当全面的方式:

    [<StructuredFormatDisplay("{AsString}")>]
    type myType = 
        {a: int}
        override m.ToString() = "hello"
        member m.AsString = m.ToString()  // a property that calls a method
    
    Run Code Online (Sandbox Code Playgroud)

顺便说一句,ToString()如果你打电话printfn "%O"而不是,总会被使用(即使是记录和工会类型)printfn "%A".


Bri*_*ian 5

嗯...我依稀记得对此进行了一些更改,但我忘记了它们是发生在 CTP (1.9.6.2) 之前还是之后。

无论如何,在CTP上,我看到

type MyType() =
    override this.ToString() = "hi"
let x = new MyType()
let xs = Array.create 25 x
printfn "%A" x
printfn "%A" xs
Run Code Online (Sandbox Code Playgroud)

当在 VFSI 窗口中评估时,会达到我想要的效果,并且

x;;
xs;;
Run Code Online (Sandbox Code Playgroud)

打印也很好。所以,我想我不清楚这与期望的有什么不同?