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"(PreText和PostText是可选的),但这实际上比ToString()因为:
PropertyName可以是任何类型的财产.如果它不是字符串,那么它也将受到结构化格式的限制.Don Syme的博客给出了以这种方式递归格式化树的示例.
它可能是计算属性.所以你实际上可以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".
嗯...我依稀记得对此进行了一些更改,但我忘记了它们是发生在 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)
打印也很好。所以,我想我不清楚这与期望的有什么不同?