2009-04-26 5 views
24

J'ai lu une bonne partie de Expert F # et je travaille sur la construction d'une application réelle. Bien que le débogage, j'ai pris l'habitude de passer des commandes de fsi comme celui-ci pour rendre les choses lisibles dans la fenêtre rempl:Comment personnaliser la sortie d'un type personnalisé en utilisant printf?

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

je voudrais étendre à travailler avec le formatter printf, donc je pouvais taper par exemple

printf "%A" instanceOfMyType 

et de contrôler la sortie pour un type personnalisé. Le livre implique que cela peut être fait (p 93, « la mise en forme de structure générique peut être étendue à travailler avec tous les types de données définis par l'utilisateur, un sujet couvert sur le site F # »), mais je n'ai pas trouvé de références quant à comment réellement accomplir ceci. Est-ce que quelqu'un sait comment? Est-ce même possible?

Edit:

J'ai inclus un exemple de code, il est un type d'enregistrement que je traite, par exemple

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

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

les deux déclarations d'impression donnent:

{a = 5;} 

Répondre

34

Il semble que la bonne façon de le faire en F # 2.0 est en utilisant l'attribut StructuredFormatDisplay, par exemple:

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

Dans cet exemple, au lieu de la valeur par défaut {a = 42;}, vous obtiendrez hello 42.

Cela fonctionne de la même manière pour objet, enregistrer et types syndicaux. Et bien que le motif doit être au format "PreText {PropertyName} PostText" (Prétexte et PostText étant en option), c'est en fait plus puissant que ToString() parce que:

  1. PropertyName peut être une propriété de tout type. Si ce n'est pas une chaîne, elle sera également soumise à un formatage structuré. Don Syme's blog donne un exemple de mise en forme récursive un arbre de cette façon.

  2. Il est peut-être une propriété calculée.Ainsi, vous pouvez réellement obtenir ToString() travailler pour les types d'enregistrement et des syndicats, mais dans une volte-ronde plutôt moyen:

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

Par ailleurs, ToString() sera toujours utilisé (même pour le dossier et les types syndicaux) si vous appelez printfn "%O" au lieu de printfn "%A".

+0

BTW, crédit à @Brian pour l'affichage de ces liens dans un commentaire de suivi à sa réponse. Je pensais juste que ça valait la peine d'étoffer pour quelqu'un d'autre qui vient chercher. –

4

Hmm ... Je me rappelle vaguement quelques changements à ce sujet, mais j'oublie si elles se sont passées avant ou après la CTP (1.9.6.2).

Dans tous les cas, le CTP, je vois que

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

lorsqu'il est évalué dans la fenêtre VFSI fait ce que je veux, et que

x;; 
xs;; 

aussi bien imprime. Donc, je suppose que je ne sais pas comment cela diffère de ce qui est désiré?

+0

Merci; voir mon édition à l'article d'origine, c'est un type d'enregistrement avec une fonction membre ajouté, et se comporte différemment d'un type de classe ... – flatline

+1

@Brian, oui, cela devrait fonctionner, mais comme le dit flatline, cela ne fonctionne pas avec union et les types d'enregistrement. J'ai couru il y a un moment: http://cs.hubfs.net/forums/post/9163.aspx (je ne me souviens pas si j'ai envoyé quelque chose à fsbugs quand je n'ai pas eu de suivi, désolé) –

+0

Voir aussi 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 et http://msdn.microsoft.com/en-us/library/ee370334.aspx – Brian

-1

Si vous remplacez la méthode ToString, qui devrait le faire.

Questions connexes