2009-04-26 7 views
24

Przeczytałem dobry fragment Expert F # i pracuję nad budową rzeczywistej aplikacji. Podczas debugowania, mam przyzwyczajeni do przechodzącej polecenia FSI tak aby rzeczy czytelne w oknie repl:Jak dostosować dane wyjściowe niestandardowego typu za pomocą printf?

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

chciałbym rozszerzyć to do pracy z formatyzatora printf, więc mogę wpisać np

printf "%A" instanceOfMyType 

i kontrolować dane wyjściowe dla niestandardowego typu. Książka sugeruje, że można to zrobić (s. 93, "Ogólne formatowanie strukturalne można rozszerzyć do pracy z dowolnymi typami danych zdefiniowanymi przez użytkownika, tematem omówionym na stronie F #"), ale nie udało mi się znaleźć żadnych odniesień co do jak faktycznie to osiągnąć. Czy ktoś wie jak? Czy to możliwe?

Edit:

powinno mam włączone próbkę kodu, jest to typ rekordu, że mam do czynienia, na przykład

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

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

oba zdania drukowania Wydajność:

{a = 5;} 

Odpowiedz

34

Wygląda na to dobry sposób, żeby to zrobić w C# 2.0 jest za pomocą atrybutu StructuredFormatDisplay, na przykład:

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

W tym przykładzie, zamiast domyślnego {a = 42;}, co można uzyskać hello 42.

Działa to w ten sam sposób dla typów obiektów, rekordów i połączeń. I chociaż wzór musi być formatu "PreText {PropertyName} PostText" (pretekstem i PostText jest opcjonalny), to jest rzeczywiście bardziej wydajne niż ToString() ponieważ:

  1. PropertyName może być własnością dowolnego typu. Jeśli nie jest ciągiem, to również będzie podlegać formatowaniu strukturalnemu. Don Syme's blog podaje przykład rekurencyjnego formatowania drzewa w ten sposób.

  2. Może to być obliczona właściwość.Więc można rzeczywiście dostać ToString() pracować dla płytowych i związków typów, choć w dość okrągłym o sposób:

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

Nawiasem mówiąc, ToString() zawsze będzie używany (nawet do rekordowych i związków typów) jeśli wywołasz printfn "%O" zamiast printfn "%A".

+0

BTW, przyznanie @Brian za opublikowanie tych linków w komentarzu uzupełniającym do jego odpowiedzi. Po prostu pomyślałem, że warto dla kogoś, kto przychodzi na poszukiwania, warto się spieszyć. –

4

Hmm ... ja niejasno przypomnieć pewne zmiany, ale nie pamiętam, czy się przed lub po CTP (1.9.6.2).

W każdym razie, na CTP, widzę, że

type MyType() = 
    override this.ToString() = "hi" 
let x = new MyType() 
let xs = Array.create 25 x 
printfn "%A" x 
printfn "%A" xs 

gdy oceniano w oknie VFSI robi to, co bym chciał, i że

x;; 
xs;; 

drukuje też ładnie. Sądzę więc, że nie jestem pewien, jak to się różni od tego, co jest pożądane?

+0

Dzięki; zobacz moją edycję do pierwotnego postu, jest to typ rekordu z dodaną funkcją członka i zachowuje się inaczej niż typ klasy ... – flatline

+1

@Brian, tak, to powinno działać, ale jak mówi linia, to nie działa w związku i typy rekordów. Wpadłem na to jakiś czas temu: http://cs.hubfs.net/forums/post/9163.aspx (nie pamiętam, czy wysłałem coś do fsbugs, gdy nie otrzymałem żadnych odpowiedzi, przepraszam) –

+0

Zobacz także 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 i http://msdn.microsoft.com/en-us/library/ee370334.aspx – Brian

-1

Jeśli zastąpisz metodę ToString, powinno to zrobić.

Powiązane problemy