Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
F# admite el formato con comprobación de tipos de texto sin formato mediante printffunciones relacionadas , printfn, sprintfy .
Por ejemplo
dotnet fsi
> printfn "Hello %s, %d + %d is %d" "world" 2 2 (2+2);;
proporciona la salida
Hello world, 2 + 2 is 4
F# también permite dar formato a los valores estructurados como texto sin formato. Por ejemplo, considere el ejemplo siguiente que da formato a la salida como una presentación similar a una matriz de tuplas.
dotnet fsi
> printfn "%A" [ for i in 1 .. 5 -> [ for j in 1 .. 5 -> (i, j) ] ];;
[[(1, 1); (1, 2); (1, 3); (1, 4); (1, 5)];
[(2, 1); (2, 2); (2, 3); (2, 4); (2, 5)];
[(3, 1); (3, 2); (3, 3); (3, 4); (3, 5)];
[(4, 1); (4, 2); (4, 3); (4, 4); (4, 5)];
[(5, 1); (5, 2); (5, 3); (5, 4); (5, 5)]]
El formato de texto sin formato estructurado se activa cuando se usa el %A formato en printf cadenas de formato.
También se activa al dar formato a la salida de valores en F# interactivo, donde la salida incluye información adicional y además se puede personalizar.
El formato de texto sin formato también es observable a través de las llamadas a x.ToString() en valores de unión y registro de F#, incluidos los que se producen implícitamente en la depuración, el registro y otras herramientas.
Comprobación de cadenas de printfformato
Se notificará un error en tiempo de compilación si se usa una printf función de formato con un argumento que no coincide con los especificadores de formato printf en la cadena de formato. Por ejemplo
sprintf "Hello %s" (2+2)
proporciona la salida
sprintf "Hello %s" (2+2)
----------------------^
stdin(3,25): error FS0001: The type 'string' does not match the type 'int'
Técnicamente, al usar printf y otras funciones relacionadas, una regla especial en el compilador de F# comprueba el literal de cadena pasado como cadena de formato, lo que garantiza que los argumentos posteriores aplicados son del tipo correcto para que coincida con los especificadores de formato usados.
Especificadores de formato para printf
Las especificaciones de formato para printf los formatos son cadenas con % marcadores que indican el formato. Los marcadores de posición de formato constan de %[flags][width][.precision][type] dónde se interpreta el tipo de la siguiente manera:
| Especificador de formato | Tipos | Observaciones |
|---|---|---|
%b |
bool (System.Boolean) |
Con formato o truefalse |
%s |
string (System.String) |
Con formato de contenido sin escape |
%c |
char (System.Char) |
Con formato como literal de carácter |
%d, %i |
un tipo entero básico | Con formato de entero decimal, con signo si el tipo entero básico tiene signo |
%u |
un tipo entero básico | Con formato de entero decimal sin signo |
%x, %X |
un tipo entero básico | Con formato como un número hexadecimal sin signo (a-f o A-F para dígitos hexadecimales respectivamente) |
%o |
un tipo entero básico | Con formato de número octal sin signo |
%B |
un tipo entero básico | Con formato de número binario sin signo |
%e, %E |
un tipo de punto flotante básico | Con formato de valor con signo que tiene el formato [-]d.dddde[sign]ddd donde d es un solo dígito decimal, dddd es uno o varios dígitos decimales, ddd es exactamente tres dígitos decimales y el signo es + o - |
%f, %F |
un tipo de punto flotante básico | Con formato como un valor con signo que tiene el formulario [-]dddd.dddd, donde dddd es uno o varios dígitos decimales. El número de dígitos antes del separador decimal depende de la magnitud del número y del número de dígitos después del separador decimal depende de la precisión solicitada. |
%g, %G |
un tipo de punto flotante básico | Con formato utilizando como un valor con signo impreso en %f formato o %e , lo que sea más compacto para el valor y la precisión especificados. |
%M |
un decimal valor (System.Decimal) |
Con formato mediante el "G" especificador de formato para System.Decimal.ToString(format) |
%O |
cualquier valor | Formateado mediante la conversión boxing del objeto y la llamada a su System.Object.ToString() método |
%A |
cualquier valor | Formato con formato de texto sin formato estructurado con la configuración de diseño predeterminada |
%a |
cualquier valor | Requiere dos argumentos: una función de formato que acepta un parámetro de contexto y el valor, y el valor concreto que se va a imprimir. |
%t |
cualquier valor | Requiere un argumento: una función de formato que acepta un parámetro de contexto que genera o devuelve el texto adecuado. |
%% |
(ninguno) | No requiere argumentos e imprime un signo de porcentaje sin formato: % |
Los tipos enteros básicos son byte (), (System.SByteSystem.Byte), sbyte (), int16 (System.Int16), uint16 (System.UInt16), int32 (System.Int32), uint32 (System.UInt32), int64 (System.Int64), uint64 (), nativeint (System.UInt64System.IntPtr) y unativeint (System.UIntPtr).
Los tipos de punto flotante básicos son float (System.Double), float32 (System.Single) y decimal (System.Decimal).
El ancho opcional es un entero que indica el ancho mínimo del resultado. Por ejemplo, %6d imprime un entero, prefijo con espacios para rellenar al menos seis caracteres. Si width es *, se toma un argumento entero adicional para especificar el ancho correspondiente.
Las marcas válidas son:
| Bandera | Efecto |
|---|---|
0 |
Agregar ceros en lugar de espacios para componer el ancho necesario |
- |
La izquierda justifica el resultado dentro del ancho especificado |
+ |
Agregue un + carácter si el número es positivo (para que coincida con un - signo para los negativos) |
| carácter de espacio | Agregue un espacio adicional si el número es positivo (para que coincida con un signo "-" para los negativos) |
La marca printf # no es válida y se notificará un error en tiempo de compilación si se usa.
Los valores tienen el formato de referencia cultural invariable. La configuración de referencia cultural es irrelevante para dar printf formato, excepto cuando afectan a los resultados y %O%A al formato. Para obtener más información, consulte formato de texto sin formato estructurado.
%A formateo
El %A especificador de formato se usa para dar formato a los valores de forma legible y también puede ser útil para notificar información de diagnóstico.
Valores primitivos
Al aplicar formato al texto sin formato mediante el %A especificador, los valores numéricos de F# tienen formato con sufijo y referencia cultural invariable. Los valores de punto flotante tienen el formato de 10 posiciones de precisión de punto flotante. Por ejemplo
printfn "%A" (1L, 3n, 5u, 7, 4.03f, 5.000000001, 5.0000000001)
Produce
(1L, 3n, 5u, 7, 4.03000021f, 5.000000001, 5.0)
Cuando se usa el %A especificador, las cadenas tienen formato entre comillas. Los códigos de escape no se agregan y, en su lugar, se imprimen los caracteres sin formato. Por ejemplo
printfn "%A" ("abc", "a\tb\nc\"d")
Produce
("abc", "a b
c"d")
Valores de .NET
Al aplicar formato a texto sin formato mediante el %A especificador, los objetos .NET que no son de F# tienen formato mediante x.ToString() la configuración predeterminada de .NET dada por System.Globalization.CultureInfo.CurrentCulture y System.Globalization.CultureInfo.CurrentUICulture. Por ejemplo
open System.Globalization
let date = System.DateTime(1999, 12, 31)
CultureInfo.CurrentCulture <- CultureInfo.GetCultureInfo("de-DE")
printfn "Culture 1: %A" date
CultureInfo.CurrentCulture <- CultureInfo.GetCultureInfo("en-US")
printfn "Culture 2: %A" date
Produce
Culture 1: 31.12.1999 00:00:00
Culture 2: 12/31/1999 12:00:00 AM
Valores estructurados
Al aplicar formato a texto sin formato mediante el %A especificador, la sangría de bloques se usa para listas y tuplas de F#. Esto se muestra en el ejemplo anterior.
También se usa la estructura de matrices, incluidas matrices multidimensionales. Las matrices unidimensionales se muestran con [| ... |] sintaxis. Por ejemplo
printfn "%A" [| for i in 1 .. 20 -> (i, i*i) |]
Produce
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25); (6, 36); (7, 49); (8, 64); (9, 81);
(10, 100); (11, 121); (12, 144); (13, 169); (14, 196); (15, 225); (16, 256);
(17, 289); (18, 324); (19, 361); (20, 400)|]
El ancho de impresión predeterminado es 80. Este ancho se puede personalizar mediante un ancho de impresión en el especificador de formato. Por ejemplo
printfn "%10A" [| for i in 1 .. 5 -> (i, i*i) |]
printfn "%20A" [| for i in 1 .. 5 -> (i, i*i) |]
printfn "%50A" [| for i in 1 .. 5 -> (i, i*i) |]
Produce
[|(1, 1);
(2, 4);
(3, 9);
(4, 16);
(5, 25)|]
[|(1, 1); (2, 4);
(3, 9); (4, 16);
(5, 25)|]
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]
Si se especifica un ancho de impresión de 0, no se usa ningún ancho de impresión. Se producirá una sola línea de texto, excepto cuando las cadenas incrustadas de la salida contengan saltos de línea. Por ejemplo
printfn "%0A" [| for i in 1 .. 5 -> (i, i*i) |]
printfn "%0A" [| for i in 1 .. 5 -> "abc\ndef" |]
Produce
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]
[|"abc
def"; "abc
def"; "abc
def"; "abc
def"; "abc
def"|]
Se usa un límite de profundidad de 4 para los valores de secuencia (IEnumerable), que se muestran como seq { ...}. Se usa un límite de profundidad de 100 para los valores de lista y matriz.
Por ejemplo
printfn "%A" (seq { for i in 1 .. 10 -> (i, i*i) })
Produce
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]
La sangría de bloques también se usa para la estructura de los valores de registro público y unión. Por ejemplo
type R = { X : int list; Y : string list }
printfn "%A" { X = [ 1;2;3 ]; Y = ["one"; "two"; "three"] }
Produce
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Si %+A se usa, la estructura privada de registros y uniones también se revela mediante la reflexión. Por ejemplo
type internal R =
{ X : int list; Y : string list }
override _.ToString() = "R"
let internal data = { X = [ 1;2;3 ]; Y = ["one"; "two"; "three"] }
printfn "external view:\n%A" data
printfn "internal view:\n%+A" data
Produce
external view:
R
internal view:
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Valores grandes, cíclicos o profundamente anidados
Los valores estructurados de gran tamaño tienen el formato de un número máximo de nodos de objetos generales de 10000.
Los valores profundamente anidados tienen un formato de profundidad de 100. En ambos casos ... se usa para evitar parte de la salida. Por ejemplo
type Tree =
| Tip
| Node of Tree * Tree
let rec make n =
if n = 0 then
Tip
else
Node(Tip, make (n-1))
printfn "%A" (make 1000)
genera una salida grande con algunas partes elided:
Node(Tip, Node(Tip, ....Node (..., ...)...))
Los ciclos se detectan en los gráficos de objetos y ... se usan en lugares donde se detectan ciclos. Por ejemplo
type R = { mutable Links: R list }
let r = { Links = [] }
r.Links <- [r]
printfn "%A" r
Produce
{ Links = [...] }
Valores diferidos, null y de función
Los valores diferidos se imprimen como Value is not created texto equivalente o cuando el valor aún no se ha evaluado.
Los valores NULL se imprimen como null a menos que el tipo estático del valor se determine como un tipo de unión donde null es una representación permitida.
Los valores de función de F# se imprimen como su nombre de cierre generado internamente, por ejemplo, <fun:it@43-7>.
Personalización del formato de texto sin formato con StructuredFormatDisplay
Cuando se usa el %A especificador, se respeta la presencia del StructuredFormatDisplay atributo en las declaraciones de tipo. Se puede usar para especificar texto suplente y propiedad para mostrar un valor. Por ejemplo:
[<StructuredFormatDisplay("Counts({Clicks})")>]
type Counts = { Clicks:int list}
printfn "%20A" {Clicks=[0..20]}
Produce
Counts([0; 1; 2; 3;
4; 5; 6; 7;
8; 9; 10; 11;
12; 13; 14;
15; 16; 17;
18; 19; 20])
Personalización del formato de texto sin formato invalidando ToString
La implementación predeterminada de ToString es observable en la programación de F#. A menudo, los resultados predeterminados no son adecuados para su uso en la presentación de información orientada al programador o en la salida del usuario, y como resultado es habitual invalidar la implementación predeterminada.
De forma predeterminada, los tipos de registro y unión de F# invalidan la implementación de ToString con una implementación que usa sprintf "%+A". Por ejemplo
type Counts = { Clicks:int list }
printfn "%s" ({Clicks=[0..10]}.ToString())
Produce
{ Clicks = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] }
Para los tipos de clase, no se proporciona ninguna implementación predeterminada de y se usa el valor predeterminado de ToString .NET, que informa del nombre del tipo. Por ejemplo
type MyClassType(clicks: int list) =
member _.Clicks = clicks
let data = [ MyClassType([1..5]); MyClassType([1..5]) ]
printfn "Default structured print gives this:\n%A" data
printfn "Default ToString gives:\n%s" (data.ToString())
Produce
Default structured print gives this:
[MyClassType; MyClassType]
Default ToString gives:
[MyClassType; MyClassType]
Agregar una invalidación para ToString puede dar un mejor formato.
type MyClassType(clicks: int list) =
member _.Clicks = clicks
override _.ToString() = sprintf "MyClassType(%0A)" clicks
let data = [ MyClassType([1..5]); MyClassType([1..5]) ]
printfn "Now structured print gives this:\n%A" data
printfn "Now ToString gives:\n%s" (data.ToString())
Produce
Now structured print gives this:
[MyClassType([1; 2; 3; 4; 5]); MyClassType([1; 2; 3; 4; 5])]
Now ToString gives:
[MyClassType([1; 2; 3; 4; 5]); MyClassType([1; 2; 3; 4; 5])]
Personalización del formato de texto sin formato con StructuredFormatDisplay y ToString
Para lograr un formato coherente para %A los especificadores de formato y %O , combine el uso de StructuredFormatDisplay con una invalidación de ToString. Por ejemplo
[<StructuredFormatDisplay("{DisplayText}")>]
type MyRecord =
{
a: int
}
member this.DisplayText = this.ToString()
override _.ToString() = "Custom ToString"
Evaluación de las definiciones siguientes
let myRec = { a = 10 }
let myTuple = (myRec, myRec)
let s1 = sprintf $"{myRec}"
let s2 = sprintf $"{myTuple}"
let s3 = sprintf $"%A{myTuple}"
let s4 = sprintf $"{[myRec; myRec]}"
let s5 = sprintf $"%A{[myRec; myRec]}"
proporciona el texto
val myRec: MyRecord = Custom ToString
val myTuple: MyRecord * MyRecord = (Custom ToString, Custom ToString)
val s1: string = "Custom ToString"
val s2: string = "(Custom ToString, Custom ToString)"
val s3: string = "(Custom ToString, Custom ToString)"
val s4: string = "[Custom ToString; Custom ToString]"
val s5: string = "[Custom ToString; Custom ToString]"
El uso de con la propiedad auxiliar DisplayText significa el hecho de StructuredFormatDisplay que myRec se omite un tipo de registro estructural durante la impresión estructurada y la invalidación de ToString() se prefiere en todas las circunstancias.
Se puede agregar una implementación de la System.IFormattable interfaz para una mayor personalización en presencia de especificaciones de formato .NET.
Impresión estructurada de F# interactivo
F# Interactive (dotnet fsi) usa una versión extendida de formato de texto sin formato estructurado para informar de los valores y permite una personalización adicional. Para obtener más información, vea F# Interactive.
Personalizar las pantallas de depuración
Los depuradores de .NET respetan el uso de atributos como DebuggerDisplay y DebuggerTypeProxy, y afectan a la visualización estructurada de objetos en ventanas de inspección del depurador.
El compilador de F# generó automáticamente estos atributos para tipos de unión y registro discriminados, pero no tipos de clase, interfaz o estructura.
Estos atributos se omiten en formato de texto sin formato de F#, pero puede resultar útil implementar estos métodos para mejorar las pantallas al depurar tipos de F#.