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;}
Foi útil?

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:

  1. 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.

  2. 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top