Disons que j'ai une ligne de code comme celle-ci:
StringContext(...).f(...)
Ce que je veux, c'est faire le 20
(la largeur du nom ) quelque chose qui lui-même peut être paramétré. Comment puis-je faire cela?
Et si je voulais également paramétrer la largeur de 7.2
pour amt
. Est-ce possible?
[Edit: J'espère mettre des choses comme 20
et 7.2
dans des variables afin qu'elles ne soient pas codées en dur dans la chaîne de format.]
J'ai essayé d'utiliser directement StringContext
, mais il semble que je ne comprends pas quelle que soit l'extension de macro qui se passe dans:
log.info(f"$name%-20s $amt%7.2f")
3 Réponses :
Vous n'êtes pas loin de la vérité:
val len = 20 val prec = 7.2 val template = s"$$name%${len}s $$amt%${prec}f"
donne:
| James 1234,12 |
En ce qui concerne le passage de 20 et 7.2 en paramètre: le modèle peut être généré comme:
val amt= 1234.1234d val name = "James" println(f"|$name%20s $amt%7.2f|")
ce qui donne:
$ name% 20 $ amt% 7.2f
Mais l'interpolation de chaîne ne semble pas être la solution car même désugée dans StringContext, elle se fait au moment de la compilation, puis
s "$ template
renvoie $ name% 20s $ amt% 7.2f
.
Je pense que cela fonctionnait avec une autre langue
Merci, mais j'espère trouver un moyen de mettre 20 dans une variable afin que 20 ne soit pas codé en dur dans la chaîne de format.
réponse juste éditée: l'interpolation ne semble pas être la solution
vous pouvez implémenter le vôtre StringContext
remarque: s "a = $ {a}, b = $ {b}"
comme StringContext ("a =", ", b ="). s (a, b)
val amt = 1234.1234d val name = "James" val len = Format("20s") val prec = Format("7.2f") myFormat"$name%$len,$amt%$prec," //" James,1234.12,"
// test
case class Format(t: String) // this implement is not type safe in Compile time, implicit class MyFormat(val sc: StringContext) { def myFormat(args: Any*) = { val partIter = sc.parts.iterator var stringFormatArgs = List.empty[Object] val sb = new StringBuilder(partIter.next()) def impl(list: List[Any]): Unit = { list match { case (_: Format) :: tail => throw new Exception("") case (any: Object) :: (format: Format) :: tail => sb.append(partIter.next()).append(format.t).append(partIter.next()) stringFormatArgs = any :: stringFormatArgs impl(tail) case (any: Any) :: tail => sb.append(any.toString).append(partIter.next()) impl(tail) case Nil => } } impl(args.toList) String.format(sb.toString(), stringFormatArgs.reverse: _*) } }
Vous pouvez le faire en deux parties.
s"%${nLen}s%${ff}f".format(name, amt) //res1: String = Jan 1.100
Ou en un seul passage.
val name = "Jan" val nLen = -10 //name length val amt = 1.1 val ff = 5.3 //float format s"%${nLen}s".format(name) + s"%${ff}f".format(amt) //res0: String = Jan 1.100