usar tipos tipo salida para modificadores lenguaje función formato especificadores control como codigo cadenas f# printf string-formatting f#-interactive

f# - tipos - printf(% d



¿Cómo personalizo la salida de un tipo personalizado usando printf? (3)

He leído una buena parte de Expert F # y estoy trabajando en la construcción de una aplicación real. Durante la depuración, me he acostumbrado a pasar comandos de fsi como este para hacer que las cosas sean legibles en la ventana de respuesta:

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

Me gustaría extender esto para que funcione con el formateador printf, por lo que podría escribir por ejemplo

printf "%A" instanceOfMyType

y controlar la salida para un tipo personalizado. El libro implica que esto se puede hacer (p. 93, "El formato estructural genérico se puede extender para trabajar con cualquier tipo de datos definidos por el usuario, un tema tratado en el sitio web de F #"), pero no he podido encontrar ninguna referencia sobre cómo para lograr realmente esto. ¿Alguien sabe cómo? ¿Es incluso posible?

Editar:

Debería haber incluido un ejemplo de código, es un tipo de registro con el que estoy tratando, por ejemplo,

type myType = {a: int} override m.ToString() = "hello" let t = {a=5} printfn "%A" t printfn "%A" (box t)

ambas declaraciones impresas producen:

{a = 5;}


Hmm ... Recuerdo vagamente algunos cambios en esto, pero olvido si ocurrieron antes o después de la CTP (1.9.6.2).

En cualquier caso, en el CTP, veo que

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

cuando se evalúa en la ventana VFSI hace lo que me gustaría, y eso

x;; xs;;

También se imprime muy bien. Entonces, supongo que no estoy claro en qué se diferencia esto de lo que se desea?


Parece que la forma correcta de hacerlo en F # 2.0 es mediante el uso del atributo StructuredFormatDisplay , por ejemplo:

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

En este ejemplo, en lugar del valor predeterminado {a = 42;} , obtendría hello 42 .

Esto funciona de la misma manera para los tipos de objeto, registro y unión. Y aunque el patrón debe tener el formato "PreText {PropertyName} PostText" ( PreText y PostText son opcionales), en realidad esto es más poderoso que ToString() porque:

  1. PropertyName puede ser una propiedad de cualquier tipo. Si no es una cadena, también estará sujeto a un formato estructurado. El blog de Don Syme da un ejemplo de cómo formatear recursivamente un árbol de esta manera.

  2. Puede ser una propiedad calculada. Así que realmente podría hacer que ToString() trabaje para tipos de registro y unión, aunque de una manera bastante aproximada:

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

Por cierto, ToString() siempre se utilizará (incluso para los tipos de registro y unión) si llama a printfn "%O" lugar de printfn "%A" .


Si anula el método ToString, debería hacerlo.