1

受此启发我想知道我们是否可以在 Scala 中进行类型安全的字符串插值(可能使用宏)?

例如,我想要这样的东西

def a[A] = ???
val greetFormat = f"Hi! My name is ${a[String]}. I am ${a[Int]} years old" 
greetFormat.format("Rick", 27)  // compiles
//greetFormat.format("Rick", false)  // does not compile
//greetFormat.format(27, "Rick") // does not compile
//greetFormat.format("Rick", 27, false) // does not compile
//greetFormat.format("Rick") // does not compile or is curried?
4

3 回答 3

3

字符串插值器f已经用宏实现了。

这可以在 REPL 内部演示:

scala> val b = "not a number"
b: String = not a number

scala> f"$b%02d"
<console>:9: error: type mismatch;
 found   : String
 required: Int
              f"$b%02d"
                 ^
于 2014-05-06T21:19:52.763 回答
2

只需将其包装在一个函数中。

def greet(name: String, age: Int) = s"Hi! My name is $name.  I am $age years old"
于 2014-05-06T21:12:48.800 回答
1

您可以为 f-interpolator 提供隐式:

scala> case class A(i: Int)
defined class A

scala> implicit def atoi(a: A): Int = a.i
warning: there were 1 feature warning(s); re-run with -feature for details
atoi: (a: A)Int

scala> f"${A(42)}%02d"
res5: String = 42

另请参阅Travis Brown在提取中使用正则表达式组名称的示例和解决方案。我花了大约一分钟的时间来窃取这个好主意。

"a123bc" match {
  case res @ xr"(?<c>a)(?<n>\d+)(?<s>bc)" => assert {
    res.c == 'a' && res.n == 123 && res.s == "bc"
  }
}

作为记录,在作曲方面,我想:

val a = A(Rick, 42)
val greeter = f"Hi! My name is $_. I am ${_}%d years old" 
greeter(a, a)

但对于可怜的下划线来说,这被认为太过分了。您必须像其他答案一样编写函数。

您的宏在其中查看"${a[Int]}"并编写带有Int参数的函数的表单看起来并不难实现。

f-interpolator 的其他功能包括其他静态错误检查:

scala> f"$b%.02d"
<console>:19: error: precision not allowed
              f"$b%.02d"
                   ^

并支持Formattable

scala> val ff = new Formattable { def formatTo(fmtr: Formatter, flags: Int, width: Int, precision: Int) = fmtr.format("%s","hello, world") }
ff: java.util.Formattable = $anon$1@d2e6b0b

scala> f"$ff"
res6: String = hello, world

一个快速宏可能会发出(i: Int) => f"${ new Formattable {...} }".

于 2014-05-07T05:45:04.683 回答