Como faço para personalizar a saída de um tipo personalizado usando printf?
-
16-09-2019 - |
Pergunta
Eu li através de um bom pedaço de Especialista F # e estou trabalhando na construção de uma aplicação real. Durante a depuração, me acostumei a passar comandos FSI como este para tornar as coisas legíveis na janela de repl:
fsi.AddPrinter(fun (x : myType) -> myType.ToString())
Eu gostaria de estender este trabalho com o formatador de printf, para que eu pudesse escrever por exemplo.
printf "%A" instanceOfMyType
e controle a saída para um tipo personalizado. O livro sugere que isso pode ser feito (p 93, "formatação estrutural genérico pode ser estendido para trabalhar com qualquer tipo de dados definidos pelo usuário, um tema abordado em # site da F "), mas eu não conseguiram encontrar quaisquer referências a respeito de como realmente fazer isso. Alguém sabe como? Será que é mesmo possível?
Editar:
Eu deveria ter incluído um exemplo de código, é um tipo de registro que eu estou lidando com, por exemplo.
type myType =
{a: int}
override m.ToString() = "hello"
let t = {a=5}
printfn "%A" t
printfn "%A" (box t)
ambas as declarações de impressão produzir:
{a = 5;}
Solução
Parece que o caminho certo para fazer isso na F # 2.0 é usando o StructuredFormatDisplay
atributo, por exemplo:
[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}
Neste exemplo, em vez do {a = 42;}
padrão, você teria hello 42
.
Isso funciona da mesma forma para os tipos de objeto, gravar e sindicais. E embora o padrão deve ser do "PreText {PropertyName} PostText"
formato ( PreText e PostText sendo opcional), este é realmente mais poderoso do que ToString()
porque:
-
PropertyName
pode ser uma propriedade de qualquer tipo. Se não é uma string, então ele também estará sujeito a formatação estruturada. Don Syme blogue dá um exemplo de formatação de forma recursiva uma árvore desta forma. -
Pode ser uma propriedade calculada. Então você pode realmente obter
ToString()
de trabalho para registro e de união tipos, embora de uma forma bastante rotunda:[<StructuredFormatDisplay("{AsString}")>] type myType = {a: int} override m.ToString() = "hello" member m.AsString = m.ToString() // a property that calls a method
A propósito, ToString()
será sempre utilizado (mesmo para registro e de união tipos) se você chamar printfn "%O"
vez de printfn "%A"
.
Outras dicas
Hmm ... Lembro-me vagamente algumas alterações a este, mas eu esquecer se aconteceu antes ou depois da CTP (1.9.6.2).
Em qualquer caso, na CTP, vejo que
type MyType() =
override this.ToString() = "hi"
let x = new MyType()
let xs = Array.create 25 x
printfn "%A" x
printfn "%A" xs
quando avaliado na janela de VFSI faz o que eu gostaria, e que
x;;
xs;;
também imprime bem. Então, eu acho que eu sou claro como isso difere do que é desejado?
Se você substituir o método ToString, que deve fazer.