Come faccio a personalizzare l'uscita di un tipo personalizzato utilizzando printf?
-
16-09-2019 - |
Domanda
Ho letto attraverso un buon pezzo di Expert F # e sto lavorando sulla costruzione di un effettiva applicazione. Durante il debug, mi sono abituato a passare comandi FSI come questo per rendere le cose leggibili nella finestra repl:
fsi.AddPrinter(fun (x : myType) -> myType.ToString())
desidero estendere questo per lavorare con il formattatore printf, così ho potuto tipo per esempio.
printf "%A" instanceOfMyType
e controllare l'output per un tipo personalizzato. Il libro implica che questo può essere fatto (p 93, "formattazione strutturale generico può essere esteso per funzionare con qualsiasi tipo di dati definiti dall'utente, un argomento coperto sul sito F # "), ma non sono riusciti a trovare tutti i riferimenti su come realizzare in realtà questo. Qualcuno sa come? E 'anche possibile?
Modifica
avrei incluso un esempio di codice, si tratta di un tipo di record che ho a che fare, per esempio.
type myType =
{a: int}
override m.ToString() = "hello"
let t = {a=5}
printfn "%A" t
printfn "%A" (box t)
entrambe le dichiarazioni di stampa Produzione:
{a = 5;}
Soluzione
Sembra che il modo giusto per fare questo in F # 2.0 è quello di utilizzare la StructuredFormatDisplay
attributo, per esempio:
[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}
In questo esempio, al posto del {a = 42;}
di default, si otterrebbe hello 42
.
Questo funziona allo stesso modo per i tipi di oggetto, registrare, e sindacali. E anche se il modello deve essere del formato "PreText {PropertyName} PostText"
( pretesto e PostText è facoltativo), questo è in realtà più potente di ToString()
perché:
-
PropertyName
può essere una proprietà di qualsiasi tipo. Se non è una stringa, allora sarà anche oggetto di formattazione strutturata. di Don Syme blog fornisce un esempio di formattazione ricorsivamente un albero in questo modo. -
Può essere una proprietà calcolata. Così si potrebbe effettivamente ottenere
ToString()
a lavorare per i tipi di record e sindacali, anche se in un modo su tutto l'piuttosto:[<StructuredFormatDisplay("{AsString}")>] type myType = {a: int} override m.ToString() = "hello" member m.AsString = m.ToString() // a property that calls a method
A proposito, sarà sempre utilizzato ToString()
(anche per i tipi di record e sindacali) se si chiama printfn "%O"
invece di printfn "%A"
.
Altri suggerimenti
Hmm ... Ricordo vagamente alcune modifiche a questo, ma se mi dimentico che è accaduto prima o dopo il CTP (1.9.6.2).
In ogni caso, il CTP, vedo che
type MyType() =
override this.ToString() = "hi"
let x = new MyType()
let xs = Array.create 25 x
printfn "%A" x
printfn "%A" xs
quando valutato nella finestra VFSI fa quello che vorrei, e che
x;;
xs;;
stampa anche bene. Quindi, credo che io sono chiaro come questo si differenzia da ciò che si desidera?
In caso di superamento metodo ToString, che dovrebbe fare.