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

时间:2009-04-26 22:12:19

标签: f# printf string-formatting f#-interactive

我已经阅读了很多 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)  

两个印刷语句都会产生:

{a = 5;}

3 个答案:

答案 0 :(得分:37)

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

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

在此示例中,您将获得{a = 42;}而不是默认hello 42

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

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

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

    [<StructuredFormatDisplay("{AsString}")>]
    type myType = 
        {a: int}
        override m.ToString() = "hello"
        member m.AsString = m.ToString()  // a property that calls a method
    
  3. 顺便说一下,如果您拨打ToString()而不是printfn "%O",将始终使用printfn "%A"(即使是记录和联合类型)。

答案 1 :(得分:4)

嗯......我含糊地回忆起一些变化,但我忘记了它们是否发生在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;;

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

答案 2 :(得分:-2)

如果重写ToString方法,那应该这样做。