J'ai lu sur les suites et les applications partielles; Je connais également la fonction kprintf.
Mais je ne sais toujours pas comment écrire quelque chose comme:
myPrintFunction "%s : %i" "hello" 3
quelle serait la syntaxe ici? p>
pour que je puisse l'utiliser comme:
let myPrintFunction format variable_length_arguments_list = let a = sprintf format variable_length_ argument_list do other things
Modifier:
Le code de test, basé sur la solution proposée par Scott peut être trouvé ici: https://dotnetfiddle.net/oCzcS9
3 Réponses :
open System let myPrintFunction (format: Printf.StringFormat<_>) ([<ParamArray>] args) = let a = sprintf format args a myPrintFunction "%s : %i" "hello" 3
Existe-t-il un moyen de connaître le nombre d'arguments dans «args»?
en fait, elle ne fonctionne pas lorsqu'elle est appelée depuis une classe: [FS0003] Cette valeur n'est pas une fonction et ne peut pas être appliquée. Le code étant: let Print (format: Printf.StringFormat <_>) ([
et l'appel étant: Imprimer "% s:% i" "bonjour" 3
Vous voulez donc que myPrintFunction soit une fonction membre d'une classe?
Oui; Je ne comprends pas pourquoi le code serait différent?
Ce lien violon ne semblait pas arriver au bon code.
Assurez-vous que votre fonction principale renvoie un int comme 0. Cette réponse fonctionne telle quelle, mais pas si vous essayez d'ajouter un effet secondaire comme un appel printfn
.
ce que cette fonction est censée faire, c'est prendre des paramètres, comme un printfn, générer une chaîne avec sprintf, appeler un événement et afficher le résultat. J'ai vu du code similaire en ligne avec kprintf, mais je n'ai pas très bien compris comment fonctionne kprintf
Peut-être que cela vous aidera à mieux comprendre kprintf: stackoverflow.com/a/5570101/5652483
Pour ajouter PrintF en tant que fonction membre, c'est la plus proche que je puisse obtenir. Comme vous le voyez, j'ai dû passer la chaîne de format séparément (dans le constructeur, ou j'aurais pu utiliser un setter de propriété). Je n'ai trouvé aucun moyen de passer la chaîne de format comme premier paramètre de la fonction PrintF comme je le pouvais pour une fonction gratuite (voir mon autre réponse à https://stackoverflow.com/a/58822618/5652483 ).
De plus, si je décommente la ligne this.RaiseSomeEvent msg
, alors ça casse. Je n'ai donc trouvé aucun moyen d'activer la fonction PrintF pour avoir un effet secondaire.
J'espère que quelqu'un d'autre pourra résoudre ces problèmes.
type Foo (format: Printf.StringFormat<_>) = member this.RaiseSomeEvent msg = printf "%s" msg member this.PrintF ([<ParamArray>] args) = let msg = sprintf format args //this.RaiseSomeEvent msg msg let foo = Foo("%s : %i") foo.PrintF "hello" 3
Je veux démontrer la fonction ksprintf, car celle-ci accepte une suite qui vous permettra de passer la chaîne résultante à par exemple un système de journalisation.
À des fins de démonstration, créons d'abord quelque chose qui peut prendre une seule chaîne comme entrée et le transmettre, dans ce cas à la console.
}
Alors maintenant, si writeStringToConsole est tout ce que nous avons, comment le faire accepter le formatage F #?
member _.Debugf format = dummy format member _.Verbosef format = dummy format member _.Infof format = dummy format member _.Warningf format = dummy format member _.Errorf format = dummy format member _.Fatalf format = dummy format
Exemple qui démontre que cela fonctionne.
let slogf = Printf.ksprintf let dummyLog _ = () // The parameter is the title string. let dummy format = slogf dummyLog format let getNullLogger () = { new ILogger with
edit: Quelques remarques supplémentaires
La chaîne de format doit être un littéral. C'est parce que la chaîne littérale doit être lue au moment de la compilation afin de calculer la fonction qui doit être retournée pour engloutir les valeurs / types qui suivent la chaîne de format.
Par exemple, si vous faites printToConsole "% i% s% A% A" 7 "x" myType yourType , alors vous verrez int -> string -> MyType -> YourType
dans la signature de printToConsole
là où il est utilisé.
Il existe un moyen d'utiliser des chaînes simples comme chaînes de format avec ce système, mais je ne me souviens pas comment c'est fait, et de toute façon cela gâche le type sécurité. Cela est pratique lors de l'internationalisation de chaînes, et vos chaînes de format doivent provenir d'une ressource et non d'une source F # en raison de services de traduction externes.
edit 2: Wrap, par exemple système de journalisation
J'ai créé une interface à utiliser pour divers systèmes de journalisation, qui partagent à peu près les mêmes fonctionnalités.
member _.Debugf format = slogf session.LogDebug format member _.Verbosef format = slogf session.LogVerbose format member _.Infof format = slogf session.LogMessage format member _.Warningf format = slogf session.LogWarning format member _.Errorf format = slogf session.LogError format member _.Fatalf format = slogf session.LogFatal format
...
interface ILogger with
Ensuite, une implémentation pour mon système de journalisation actuellement utilisé ressemble à ceci.
type internal SiLogger(session: Session) = let slogf = Printf.ksprintf
...
abstract member Debugf: StringFormat<'h, unit> -> 'h abstract member Verbosef: StringFormat<'h, unit> -> 'h abstract member Infof: StringFormat<'h, unit> -> 'h abstract member Warningf: StringFormat<'h, unit> -> 'h abstract member Errorf: StringFormat<'h, unit> -> 'h abstract member Fatalf: StringFormat<'h, unit> -> 'h
...
type ILogger =
Et il y a un enregistreur nul.
type DU = A | B let i = 7 let s = "thirteen" let du = B printToConsole """an int %i and a string "%s" here""" i s printToConsole """an int %i and a string "%s" and DU %A here""" i s du // OUTPUT : an int 7 and a string "thirteen" here // OUTPUT : an int 7 and a string "thirteen" and DU B here // Note that OUTPUT is also part of the actual output, // and it demonstrates how you can add e.g. a timestamp // or line number or something to the output string, without // it being part of the formatting.
...
let printToConsole format = Printf.ksprintf writeStringToConsole format
...
let writeStringToConsole (s: string) = Console.WriteLine ("OUTPUT : " + s)
Existe-t-il un moyen de savoir combien d'arguments 'format' a? Je me demande s'il est possible de détecter printToConsole "hello" en tant qu'argument unique et d'imprimer la chaîne telle quelle, ce qui réduit le besoin de printToConsole "% s" "hello"
En passant, si vous faites cela pour vous connecter à un service de production, il y a plus à faire, alors cela et d'autres exigences apparaîtront. J'envisagerais l'utilisation d'une bibliothèque de journalisation F # pour cela. J'ai dû écrire LoggerWrapper.FSharp pour créer des fonctions de journalisation qui font les choses que vous recherchez probablement lorsque vous descendez le terrier du lapin. Par exemple, si la journalisation est désactivée, il ne devrait pas tenter de créer la chaîne / d'allouer de la mémoire pour des raisons de performances - ce qui est généralement vrai pour la journalisation de débogage. kprintf fait cela sans encapsuler le tout et donc cela peut être difficile à implémenter.
Je soupçonne que l'enregistreur nul que j'ai maintenant ajouté à la réponse fera un travail qui n'est pas nécessaire. Cela pourrait être un avantage si vous voulez la charge pendant le débogage, mais vous pouvez aussi, je suppose, ajouter quelque chose comme si activé, puis format factice
. Ou simplement ne pas utiliser du tout ksprintf dans le journal nul.
Oh, et j'ai aussi des membres Debug, Verbose, etc., qui sortent simplement une chaîne sans utiliser de formatage. Pour des raisons de performances.
Est-ce que cela répond à votre question? Comment implémenter une méthode avec un nombre variable d'arguments?
Non, le système au format F # n'existe pas en C #.