Как настроить вывод пользовательского типа с помощью printf? - PullRequest
29 голосов
/ 27 апреля 2009

Я прочитал хороший кусок Expert F # и работаю над созданием реального приложения. Во время отладки я привык передавать команды fsi, подобные этой, чтобы сделать вещи разборчивыми в окне repl:

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

Я хотел бы расширить это для работы с форматтером printf, чтобы я мог напечатать, например,

printf "%A" instanceOfMyType 

и управляйте выводом для пользовательского типа. Книга подразумевает, что это можно сделать (стр. 93, «Общее структурное форматирование можно расширить для работы с любыми пользовательскими типами данных, тема на веб-сайте F # "), но я не смог найти никаких ссылок на то, как на самом деле это сделать. Кто-нибудь знает как?

Edit:

Я должен был включить пример кода, это тип записи, с которой я имею дело, например,

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

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

оба оператора печати дают:

{a = 5;}

Ответы [ 3 ]

38 голосов
/ 24 ноября 2012

Похоже, что правильный путь сделать это в F # 2.0 - использовать атрибут StructuredFormatDisplay, например:

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

В этом примере вместо значения по умолчанию {a = 42;} вы получите hello 42.

Это работает одинаково для типов объектов, записей и объединений. И хотя шаблон должен иметь формат "PreText {PropertyName} PostText" ( PreText и PostText необязательно), он на самом деле более мощный, чем ToString(), потому что:

  1. PropertyName может быть свойством любого типа. Если это не строка, она также будет подвергаться структурированному форматированию. В блоге Дона Сайма приведен пример рекурсивного форматирования дерева таким образом.

  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".

4 голосов
/ 27 апреля 2009

Хм ... Я смутно припоминаю некоторые изменения в этом, но я забываю, произошли ли они до или после ОСАГО (1.9.6.2).

В любом случае на ОСАГО я вижу, что

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;;

также хорошо печатает. Так что, думаю, мне неясно, чем это отличается от того, что нужно?

0 голосов
/ 27 апреля 2009

Если вы переопределите метод ToString, это должно быть сделано.

...