我希望我的Scala程序能够编程方式确定其脚本文件名或类名,将字符串存储在变量program
中并打印出名称。
Java有几种方法可以实现此功能。
val program = new Exception().getStackTrace.head.getFileName
根据0__的提示解析堆栈跟踪应该可以处理大部分情况,特别是当包含主方法的对象不在同名文件中时:
package utils
trait ProgramInfo {
val programInfo = try {
throw new RuntimeException("x")
} catch {
case e: RuntimeException =>
val arr = new java.io.CharArrayWriter()
val buffer = new java.io.PrintWriter(arr)
e.printStackTrace(buffer)
val trace = arr.toString
val lines = io.Source.fromString(trace)
val pat = """^.*at.*\.main\(([^:]*)(:.*)?\).*$""".r
lines.getLines().collectFirst{case pat(n, l) => n}.getOrElse("<none>")
}
}
object ProgramInfo extends ProgramInfo
println(utils.ProgramInfo.programInfo)
object A extends utils.ProgramInfo {
def main(args: Array[String]) {
println(programInfo)
}
}
无论代码是否包含在对象中,scala A.script
都可以用于脚本。同时,使用 scalac
编译并运行 scala A
也是可行的。但是,在 REPL 中运行时将返回 <none>
。
val trace
定义之后添加println(trace)
,看看是否出现.main(xxx)
。 - huynhjldef
来返回程序名称,但是Scala将 def
视为无返回值的函数。你知道得越多,你就会发现这个问题。 - mcandrepackage
语句上出了问题。 - mcandre不太确定你在寻找什么...
$ scala -e 'println( "I am " + getClass.getName )'
给我
"I am Main$$anon$1"
而且
$ scala -e 'try { sys.error( "" )} catch { case e => println( "I am " + e.getStackTrace()( 3 ))}'
给我
"I am Main.main(scalacmd2873893687624153305.scala)"
program
中,并打印出来。 - mcandregetClass.getName
将会起作用。(它也可以在一个对象中工作,但可能不会看起来像你期望的那样。) - Luigi Plinge// With help from huynhjl
// https://dev59.com/JV3Ua4cB1Zd3GeqP-jsm
import scala.util.matching.Regex.MatchIterator
object ScriptName {
val program = {
val filenames = new RuntimeException("").getStackTrace.map { t => t.getFileName }
val scala = filenames.indexOf("NativeMethodAccessorImpl.java")
if (scala == -1)
"<console>"
else
filenames(scala - 1)
}
def main(args: Array[String]) {
val prog = program
println("Program: " + prog)
}
}
#!/bin/bash
exec scala "$0" "$0" "$@"
!#
val program = args(0)
println(program)
scalac
编译器兼容的形式? - mcandre