【问题标题】:scala string interpolation with a variable length具有可变长度的scala字符串插值
【发布时间】:2016-12-07 08:48:33
【问题描述】:

我使用 scala f 字符串插值器如下:

def format(id: Int) = f"A$id%04d"
format(21)  // A0021

但是,我希望能够一劳永逸地定义一个长度(在固定为 4 之前),并获得一个函数,它将用该长度格式化字符串。 所以,而不是拥有

def format(length: Int, id: Int) = ???
f(5, 21)       // A00021

我想要这个:

def format(length: Int)(id: Int) = ???
val f = format(5)
f(21)       // A00021

如何使用 scala f 插值器或其他方法实现此功能?

更新

我并不是在寻找这样一个在运行时涉及编译器的解决方案,但我很欣赏 som-snytt 的回答。根据他的回答,这里有一个可行的解决方案:

import scala.tools.reflect._,scala.reflect.runtime._,universe._

def defFormat(length: Int): Int => String = {
  val code = raw"""(i: Int) => f"A$$i%0${length}d""""
  tb.eval(tb.parse(code)).asInstanceOf[Int => String]
}

val format = defFormat(length = 5)

format(21)

【问题讨论】:

标签: scala


【解决方案1】:
scala> def format(n: Int)(i: Int) =
     | f"A%%0${n}d" format i
format: (n: Int)(i: Int)String

scala> format(5) _
res0: Int => String = <function1>

scala> .apply(21)
res1: String = A00021

编辑:

scala> import scala.tools.reflect._,scala.reflect.runtime._,universe._
import scala.tools.reflect._
import scala.reflect.runtime._
import universe._

scala> val tb = currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@2d10e0b1

scala> def f(n: Int)(i: Int): String = {
     |   val code = raw"""f"A$${$i}%0${n}d""""
     |   tb.eval(tb.parse(code)).asInstanceOf[String]
     | }
f: (n: Int)(i: Int)String

scala> val g = f(5) _
g: Int => String = <function1>

scala> g(21)
res9: String = A00021

这实际上并没有多大帮助。你真的很想

scala> tb.typecheck(tb.parse(code))
scala.tools.reflect.ToolBoxError: reflective typecheck has failed: illegal conversion character 'k'
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:178)

如果格式不好会抛出。

scala>   val code = raw"""(i: Int) => f"A$${i}%k0${10}d""""
code: String = (i: Int) => f"A${i}%k010d"

scala> tb.typecheck(tb.parse(code))
scala.tools.reflect.ToolBoxError: reflective typecheck has failed: illegal conversion character 'k'
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:178)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:170)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$11.apply(ToolBoxFactory.scala:148)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$11.apply(ToolBoxFactory.scala:148)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$9.apply(ToolBoxFactory.scala:138)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$9.apply(ToolBoxFactory.scala:138)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$withContext$1$1.apply(ToolBoxFactory.scala:139)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$withContext$1$1.apply(ToolBoxFactory.scala:139)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$7.apply(ToolBoxFactory.scala:137)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$7.apply(ToolBoxFactory.scala:137)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1.apply(ToolBoxFactory.scala:148)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1.apply(ToolBoxFactory.scala:121)
  at scala.reflect.internal.Trees$class.wrappingIntoTerm(Trees.scala:1716)
  at scala.reflect.internal.SymbolTable.wrappingIntoTerm(SymbolTable.scala:16)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.withWrapping$1(ToolBoxFactory.scala:120)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.transformDuringTyper(ToolBoxFactory.scala:121)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.typecheck(ToolBoxFactory.scala:169)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$typecheck$2.apply(ToolBoxFactory.scala:375)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$typecheck$2.apply(ToolBoxFactory.scala:367)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:355)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:355)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.typecheck(ToolBoxFactory.scala:367)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.typecheck(ToolBoxFactory.scala:27)
  ... 32 elided

scala>   val code = raw"""(i: Int) => f"A$${i}%0${10}d""""
code: String = (i: Int) => f"A${i}%010d"

scala> tb.typecheck(tb.parse(code))
res19: tb.u.Tree =
((i: Int) => ({
  val arg$macro$9: Int = i;
  new scala.collection.immutable.StringOps("A%010d").format(arg$macro$9)
}: String))

【讨论】:

  • 是的,但是这里你使用的是格式方法,而不是 f 字符串插值器
  • 您要求使用“f 插值器或其他”。如果有帮助,我将添加工具箱暂存。
  • 所以你构建函数来检查格式,然后构建代码来评估。这与使用完整编译器生成和加载类相反,在这种情况下,您只需发出要使用的函数。
【解决方案2】:

您不能使用f 来执行此操作,因为它的全部目的是确保它可以检查格式字符串的类型错误,因此格式字符串必须是静态的。 f 可以明确支持这种情况,但事实并非如此。

可以format 设为宏,但这似乎有点矫枉过正。更不用说它必须在一个单独的模块中定义,这在这种情况下看起来很不方便。

【讨论】:

  • 在某个时候有人会问我为什么要使用这种古老的格式?答案是:因为我是古人。
猜你喜欢
  • 2021-10-14
  • 2012-05-10
  • 1970-01-01
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-24
相关资源
最近更新 更多