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

41

我已经阅读了《Expert F#》的大部分内容,并正在构建一个实际的应用程序。在调试过程中,我习惯于传递fsi命令,以便在repl窗口中使事情更加可读:

fsi.AddPrinter(fun (x : myType) -> myType.ToString())

我希望能够扩展此功能以适用于printf格式化程序,这样我就可以输入例如:
printf "%A" instanceOfMyType 

并控制自定义类型的输出。这本书暗示说可以做到这一点(第93页,“通用结构格式化可以扩展到任何用户定义的数据类型,这是F#网站上涉及的主题”),但我没有找到任何关于如何实际完成这一点的参考资料。有人知道吗?这是否可能?

编辑:

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

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

let t = {a=5}
printfn "%A" t
printfn "%A" (box t)  

两个print语句都输出:

{a = 5;}
3个回答

51

看起来在 F# 2.0 中正确的做法是使用 StructuredFormatDisplay 属性,例如:

[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}

在这个例子中,与默认的{a = 42;}不同,你会得到hello 42
对于对象、记录和联合类型,它们的工作方式相同。虽然模式必须是格式为"PreText {PropertyName} PostText"PreTextPostText是可选的),但实际上比ToString()更强大,因为:
  1. PropertyName can be a property of any type. If it is not a string, then it will also be subject to structured formatting. Don Syme's blog gives an example of recursively formatting a tree in this way.

  2. It may be a calculated property. So you could actually get ToString() to work for record and union types, though in a rather round-about way:

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

顺便提一下,如果您调用printfn "%O"而不是printfn "%A",即使是记录和联合类型,ToString()也将始终被使用。


顺便提一下,感谢@Brian在他的回答中发布这些链接。我觉得值得为其他寻找答案的人详细解释一下。 - Todd Owen
该属性/成员可以被设置为 private,以避免暴露可能会分配对象属性的对象(而不是作为方法调用)。另外,我无法使用对象方法(“未找到”)。 - Henrik

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

当在VFSI窗口中评估时,它会执行我想要的操作。

x;;
xs;;

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

谢谢;请看我对原帖的编辑,这是一个添加了成员函数的记录类型,与类类型的行为不同... - flatline
1
@Brian,是的,那应该可以,但正如flatline所说,它不能与联合和记录类型一起使用。我在一段时间前遇到了这个问题:http://cs.hubfs.net/forums/post/9163.aspx(不记得是否在没有得到任何跟进时向fsbugs发送了什么,抱歉)。 - Kurt Schelfthout
请参见http://blogs.msdn.com/b/dsyme/archive/2010/01/08/some-tips-and-tricks-for-formatting-data-in-f-interactive-and-a-in-sprintf-printf-fprintf.aspx和http://msdn.microsoft.com/en-us/library/ee370334.aspx。 - Brian

-2
如果你重写 ToString 方法,那就可以了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接