简体   繁体   English

如何将元组应用于Scala中的格式字符串?

[英]How to apply tuple to a format string in Scala?

Edit1 EDIT1

I have already seen this question: Applying a function to a tuple in Scala 我已经看到了这个问题: 将函数应用于Scala中的元组

Ideally I would simply like to do like this: 理想情况下,我只想这样做:

scala> val t = ("A", "B", "C")
t: (java.lang.String, java.lang.String, java.lang.String) = (A,B,C)

scala> "%-10s %-50s %s".format(t) // or some closer syntax

Which should give output as 哪个应该输出为

res12: String = A          B                                                  C

Edit2 EDIT2

Or in some sense Scala complier should be able to infer that I am actually calling with correct arguments and types such that 或者在某种意义上,Scala编译器应该能够推断出我实际上正在调用正确的参数和类型

"%-10s %-50s %s".format(t.untuple) expands to "%-10s %-50s %s".format(t._1, t._2, t._3) "%-10s %-50s %s".format(t.untuple)扩展为"%-10s %-50s %s".format(t._1, t._2, t._3)

Can I use a macro to do this? 我可以使用宏来执行此操作吗?

Original question follows 原始问题如下

I have a tuple which I use for formatting a string: 我有一个元组用于格式化字符串:

scala> val t = ("A", "B", "C")
t: (java.lang.String, java.lang.String, java.lang.String) = (A,B,C)

scala> "%-10s %-50s %s".format(t.productElements.toList: _*)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
res10: String = A          B                                                  C

scala> "%-10s %-50s %s".format(t._1, t._2, t._3)
res11: String = A          B                                                  C

All works fine till now. 到目前为止一切正常。 But this fails: 但这失败了:

scala> val f = "%-10s %-50s %s".format(_)
f: Any* => String = <function1>

scala> f(t.productElements.toList: _*)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
java.util.MissingFormatArgumentException: Format specifier '-50s'
    at java.util.Formatter.format(Formatter.java:2487)
    at java.util.Formatter.format(Formatter.java:2423)
    at java.lang.String.format(String.java:2797)
    at scala.collection.immutable.StringLike$class.format(StringLike.scala:270)
    at scala.collection.immutable.StringOps.format(StringOps.scala:31)
    at $anonfun$1.apply(<console>:7)
    at $anonfun$1.apply(<console>:7)
    at .<init>(<console>:10)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:744)

This also fails: 这也失败了:

scala> f.apply(t)
java.util.MissingFormatArgumentException: Format specifier '-50s'
    at java.util.Formatter.format(Formatter.java:2487)
    at java.util.Formatter.format(Formatter.java:2423)
    at java.lang.String.format(String.java:2797)
    at scala.collection.immutable.StringLike$class.format(StringLike.scala:270)
    at scala.collection.immutable.StringOps.format(StringOps.scala:31)
    at $anonfun$1.apply(<console>:7)
    at $anonfun$1.apply(<console>:7)
    at .<init>(<console>:10)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:744)

What am I doing wrong ? 我究竟做错了什么 ? How can I apply tuple parameters to a "varagrs" style function? 如何将元组参数应用于“varagrs”样式函数?

The problem is in lambda definition 问题出在lambda定义中

val f = "%-10s %-50s %s".format(_)

is equivalent to: 相当于:

val f = x => ("%-10s %-50s %s".format)(x) , val f = x => ("%-10s %-50s %s".format)(x)

So you're just passing sequence as first argument here. 所以你只是在这里传递序列作为第一个参数。

Correct lambda is: (x: Seq[Any]) => ("%-10s %-50s %s".format)(x: _*) or even just val f: Seq[Any] => String = "%-10s %-50s %s".format 正确的lambda是: (x: Seq[Any]) => ("%-10s %-50s %s".format)(x: _*)或者甚至只是val f: Seq[Any] => String = "%-10s %-50s %s".format

Examples: 例子:

scala> val f = x => ("%-10s %-50s %s".format)(x)
f: Seq[Any] => String = <function1>

scala> f(Seq(1,2,3))
java.util.MissingFormatArgumentException: Format specifier '-50s'

scala> val f: Seq[Any] => String = "%-10s %-50s %s".format
f: Seq[Any] => String = <function1>

scala> f(Seq(1,2,3))
res75: String = 1          2                                                  3

Unfortunately scala don't understand ("%-10s %-50s %s".format)(_: _*) , so you can't use underscore. 不幸的是scala不明白("%-10s %-50s %s".format)(_: _*) ,所以你不能使用下划线。

What's interesting here: if you try to do same using underscore without apply - you won't have to specify _* explicitly: 这里有趣的是:如果您尝试使用下划线而不应用 - 您将不必明确指定_ *:

scala> val f = ("%-10s %-50s %s": scala.collection.immutable.StringLike[_]).format _
f: Seq[Any] => String = <function1>

scala> f(Seq(1,2,3))
res81: String = 1          2                                                  3

But you have to specify type class explicitly because function _ construction doesn't work with implicits . 但是您必须明确指定类型类,因为function _构造不适用于implicits

You can define f as follows: 您可以按如下方式定义f

def f(t: Product) = "%-10s %-50s %s".format(t.productIterator.toList: _*)

then you can apply it to t : 然后你可以把它应用到t

scala> f(t)
res1: String = A          B                                                  C

What is Product 什么是Product

scala.Product is a trait which is implemented by many classes, for example Product2 and Product3 . scala.Product是一个由许多类实现的trait ,例如Product2Product3 These classes in turn are super types of Tuple2 and Tuple3 respectively. 这些类又分别是Tuple2Tuple3超类型。

So briefly, any tuple is a Product . 简而言之,任何元组都是Product That's why productIterator is available on all tuples. 这就是为什么productIterator适用于所有元组的原因。

So in order to use a tuple as vararg one way is to use the productIterator and convert it to List by invoking the toList method. 因此,为了使用元组作为vararg,一种方法是使用productIterator并通过调用toList方法将其转换为List

A better signature 更好的签名

Maybe the following signature is a better signature for your function: 也许以下签名是您的功能更好的签名:

 def f(fmt: String)(t:Product) = fmt(t.productIterator.toList: _*)

Now you can apply (or partially apply) it to get the desired result : 现在您可以应用(或部分应用)它来获得所需的结果:

val res = f("%-10s %-50s %s")(t)
val newFormatter = f("%-10s %-40s %s")_
val newResult = newFormatter(t)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM