Как мне настроить вывод пользовательского типа с помощью printf?

StackOverflow https://stackoverflow.com/questions/791706

Вопрос

Я прочитал изрядный кусок Эксперт 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;}
Это было полезно?

Решение

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

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

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

Это работает одинаково для типов object, record и union.И хотя шаблон должен быть такого формата "PreText {PropertyName} 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".

Другие советы

Хм...Я смутно припоминаю некоторые изменения в этом, но я забыл, произошли ли они до или после CTP (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;;

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top