FSC每次都重新编译我的.scala文件,即使没有必要 - 我可以编译它两次而不需要在两次尝试之间编辑任何内容并重新编译它们!例如,我有2个文件
Hello.scala
class Hello{
print("hello")
}
Run Code Online (Sandbox Code Playgroud)
和Tokens.scala:
abstract class Token(val str: String, val start: Int, val end: Int)
{override def toString = getClass.getSimpleName + "(" + "[" + start + "-" + end + "]" + str + ")"}
class InputToken(str: String, start: Int, end: Int)
extends Token(str, start, end)
class ParsedToken(str: String, start: Int, end: Int, val invisible: Boolean)
extends Token(str, start, end)
Run Code Online (Sandbox Code Playgroud)
当我要求ant从头编译项目时,我看到以下输出:
ant compile
init:
[mkdir] Created dir: D:\projects\Test\build\classes
[mkdir] Created dir: D:\projects\Test\build\test\classes
compile:
[fsc] …
Run Code Online (Sandbox Code Playgroud) Scala编译器的帮助菜单(2.9.2)说
-print Print program with Scala-specific features removed.
Run Code Online (Sandbox Code Playgroud)
但是使用该-print
选项的以下调用显示了Scala特定的功能:
C:\Users\John\Test Scala Project\src\main\scala>type test.scala
trait A
C:\Users\John\Test Scala Project\src\main\scala>scalac -print test.scala
[[syntax trees at end of cleanup]]// Scala source: test.scala
package <empty> {
abstract trait A extends java.lang.Object
}
Run Code Online (Sandbox Code Playgroud)
为什么特征仍然显示?我原本期望纯Java代码.
这听起来很尴尬.我的目的是了解Scala如何处理以Java风格编写的包语句.为此,我写了一个小示例类(我将DinnerTimeP.scala命名如下:
package dinnertime
class Dinner {
val veggie = "broccoli"
def announceDinner(veggie: String) {
println("Dinner happens to be tasteless " + veggie + " soup")
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个名为scaladev的文件夹,我在其下创建了包文件夹dinnertime.在这个包下生活DinnerTimeP.scala.在DOS命令中,我然后导航到dinnertime并使用scalac编译文件DinnerTimeP(名称听起来很傻),如下所示.
C:\scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime>set CLASSPATH=.;C:\scala- 2.9.1.final\scala-2.9.1.final\scaladev
C:\scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime>scalac DinnerTimeP.scala
Run Code Online (Sandbox Code Playgroud)
我希望在dinnertime文件夹下找到Dinner.class并坐在源文件DinnerTimeP.scala旁边.为了确认我的理解,我在同一个文件夹下创建了一个HelloWorld.java程序:
package dinnertime;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
Run Code Online (Sandbox Code Playgroud)
}
我在命令行上编译了HelloWorld.java,如下所示:C:\ scala-2.9.1.final\scala-2.9.1.final\scaladev\dinnertime> javac HelloWorld.java
HelloWorld.class文件就在其源文件旁边生成.这是我想用Scala源文件及其编译文件看到的确切情况.相反,我在包文件夹dinnertime中看到了Scala生成的新包文件夹.
这可能是天真的.我可能背叛了对Scala和软件包的基本理解,但我对此行为感到困惑.这是我无法向自己解释的问题:为什么为新生成的类文件创建嵌套包.基于我自己的真诚努力,这是我希望解决的问题因为我目前对Scala的经验有限,我已经请求Scala大师在stackoverflow上帮助我理解发生了什么为什么?有没有理由让这个嵌套包由Scala而不是Java创建?
我开始为Scala中的X500PrincipalBuilder类编写单元测试.这是我的测试代码:
import org.junit.runner.RunWith
import org.scalatest.WordSpec
import org.scalatest.junit.JUnitRunner
import org.scalatest.matchers.ShouldMatchers._
import org.scalatest.prop.PropertyChecks._
import javax.security.auth.x500.X500Principal
@RunWith(classOf[JUnitRunner])
class X500PrincipalBuilderTest extends WordSpec {
"An X500 Principal Builder" when {
"given a list of attributes" should {
"properly build an X500 Principal" in {
val table = Table(
("expected", "attributes"),
("CN=Duke", List("CN" -> "Duke"))
)
forAll (table) { (expected, attributes) =>
val b = new X500PrincipalBuilder
attributes foreach { case (key, value) => b addAttribute (key, value) }
b.build should equal (new X500Principal(expected))
}
} …
Run Code Online (Sandbox Code Playgroud) 您认为打印出来的是什么?
val foo: String = "foo" + foo
println(foo)
val foo2: Int = 3 + foo2
println(foo2)
Run Code Online (Sandbox Code Playgroud)
回答:
foonull
3
Run Code Online (Sandbox Code Playgroud)
为什么?规范中是否有一部分描述/解释了这一点?
编辑:澄清我的惊讶 - 我确实意识到这foo
是未定义的val foo: String = "foo" + foo
,这就是为什么它有一个默认值null
(整数为零).但这似乎不是很"干净",我在这里看到的意见与我一致.我希望编译器能阻止我做那样的事情.它在某些特定情况下确实有意义,例如在定义Stream
s本质上是懒惰的时候,但对于字符串和整数,我会期望由于重新分配给val或者告诉我我正在尝试使用未定义的值而阻止我,就像我写的那样val foo = whatever
(假设whatever
从未定义).
为了进一步复杂化,@ dk14指出此行为仅适用于表示为字段的值,并且不会发生在块内,例如
val bar: String = {
val foo: String = "foo" + foo // error: forward reference extends...
"bar"
}
Run Code Online (Sandbox Code Playgroud) 我正在测试我的插件,在进程中运行它像这样:
type PluginMessage = StoreReporter#Info
def runPlugin(fileName: String): List[PluginMessage] = {
val settings = new Settings
settings.outputDirs setSingleOutput (curDir + "/target")
settings.classpath.tryToSet(List(
"project/boot/scala-" + scalaVersion + "/lib/scala-compiler.jar" +
":project/boot/scala-" + scalaVersion + "/lib/scala-library.jar"))
val reporter = new StoreReporter
val compiler = new Global(settings, reporter) {
override protected def computeInternalPhases() {
super.computeInternalPhases
for (phase <- new AlacsPlugin(this).components)
phasesSet += phase
}
}
(new compiler.Run).compile(List(testPrefix + fileName))
reporter.infos.toList
}
Run Code Online (Sandbox Code Playgroud)
但是,鉴于速度慢,scalac
我真的希望编译在某个阶段之后结束(特别是在我的插件运行之后).不幸的Global.cancel
是没有预期的效果.我怎么能这样做?
有趣的是,在启用这些选项后,我们的构建似乎更慢.我在网上搜索了一下,试图做一些比较,但没有找到结论.想知道是否有人知道.
将Scala文件反编译为Java代码时,经常会遇到用ScalaSignature
s 注释的类。这些似乎只有一个注释值,即经过某种程度编码的String。为什么Scala编译器会创建这样的奇数构造,而不是Attribute
在class
文件中使用custom ?
我有一个生成jar的scala项目.我正在尝试在Java项目中使用jar.奇怪的是,当签名编译为.class文件时,签名正在丢失泛型类型信息.
def foo(x:List[Long]) = ...
Run Code Online (Sandbox Code Playgroud)
Lscala/collection/immutable/List<Ljava/lang/Object;>
在.class文件中生成一个方法.
它也一样
def foo(x:java.util.List[Long]) = ...
Run Code Online (Sandbox Code Playgroud)
.class文件说方法签名是
Ljava/util/List<Ljava/lang/Object;>
真正的问题是,当我在Java项目中使用这个jar时,我必须使用List<Object>
而不是List<Long>
我想要的.当然我可以施展它,但我宁愿不必.有任何想法吗?
我使用scala版本2.11.7
我有这样的事情:
case class Box[A](x: A) {
def flatMap[B](f: A => GenTraversableOnce[B]): GenTraversableOnce[B] =
f(x)
def flatMap[B](f: A => Box[B]): Box[B] =
f(x)
def map[B](f: A => B): Box[B] =
Box(f(x))
}
object Box {
for {
i <- Box(0)
j <- Box(1)
} yield i + j
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在Scala 2.12.4中编译得很好,但是不能在Scala 2.11.12中编译:
[error] Box.scala:10: missing parameter type
[error] i <- Box(0)
[error] ^
[error] one error found
[error] (core/compile:compileIncremental) Compilation failed
Run Code Online (Sandbox Code Playgroud)
为什么?我究竟做错了什么??
然后我尝试了:
for {
i: Int <- Box(0) …
Run Code Online (Sandbox Code Playgroud) 使用build.sbt文件,如:
ThisBuild / organization := "com.company"
ThisBuild / version := "1.0.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.11.12"
Global / concurrentRestrictions += Tags.limit(Tags.Test, 1)
Global / scalacOptions ++= Seq("-Ypartial-unification",
"-unchecked",
"-Xfatal-warnings",
"-Ywarn-dead-code",
"-Ywarn-inaccessible",
"-Ywarn-unused",
"-Ywarn-unused-import",
"-Ywarn-macros:after")
Run Code Online (Sandbox Code Playgroud)
我[error] bad option: '-Ywarn-macros:none'
跑完了sbt clean compile
如果没有-Ywarn-macros:after
,未使用的导入警告会在使用Circe宏的文件中引发虚假警告,例如:import io.circe.{ Decoder, Encoder }
.
Groovy带有一个名为的编译器groovyc
.对于每个脚本,groovyc
生成一个扩展的类groovy.lang.Script
,其中包含一个main方法,以便Java可以执行它.已编译类的名称与正在编译的脚本的名称相匹配.
例如,使用此HelloWorld.groovy
脚本:
println "Hello World"
Run Code Online (Sandbox Code Playgroud)
这就像这段代码:
class HelloWorld extends Script {
public static void main(String[] args) {
println "Hello World"
}
}
Run Code Online (Sandbox Code Playgroud)
Scala带有一个名为的编译器scalac
.
例如,使用相同的HelloWorld.scala
脚本:
println("Hello World")
Run Code Online (Sandbox Code Playgroud)
代码无效scalac
,因为编译器期望类或对象定义,但在Scala REPL Interpreter中工作.怎么可能?在执行之前它是否包含在类中?
scala ×12
scalac ×12
java ×3
circe ×1
compilation ×1
generics ×1
groovy ×1
packages ×1
sbt ×1
scala-2.10 ×1
scala-2.11 ×1
scala-2.12 ×1
scala-script ×1