38

我已经阅读了大量的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;}
4

3 回答 3

48

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

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

在此示例中{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
    

顺便说一句,ToString()如果您调用printfn "%O"而不是printfn "%A".

于 2012-11-23T23:51:44.953 回答
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;;

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

于 2009-04-26T23:00:49.570 回答
-2

如果您覆盖 ToString 方法,那应该可以。

于 2009-04-26T23:01:41.237 回答