要创建一个可以在Scala中用于理解的新类,似乎所有你需要做的就是定义一个map函数:
scala> class C[T](items: T*) {
| def map[U](f: (T) => U) = this.items.map(f)
| }
defined class C
scala> for (x <- new C(1 -> 2, 3 -> 4)) yield x
res0: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))
Run Code Online (Sandbox Code Playgroud)
但这仅适用于简单的for循环,其中左侧没有模式匹配<-.如果您尝试在那里进行模式匹配,则会收到filter未定义方法的投诉:
scala> for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v
<console>:7: error: value filter is not a member of C[(Int, Int)]
for ((k, v) <- new C(1 -> 2, 3 -> …Run Code Online (Sandbox Code Playgroud) 我有许多大文件,我想处理除了每个文件中的最后一行以外的所有文件.如果文件很小,我可以转换为TraversableLike并使用"init"方法,例如:
lines.toList.init
Run Code Online (Sandbox Code Playgroud)
但是文件很大所以我需要将事物保存为迭代器.有没有一种简单的方法可以在迭代器上获得类似"init"的内容?我正在考虑以下内容,但我不相信它会一直有效:
lines.takeWhile(_ => lines.hasNext)
Run Code Online (Sandbox Code Playgroud) 我test-jar在多模块项目中使用依赖项时遇到问题.例如,当我声明cleartk-syntax模块依赖于cleartk-token模块时test-jar(完整代码在这里):
<modelVersion>4.0.0</modelVersion>
<groupId>org.cleartk</groupId>
<artifactId>cleartk-syntax</artifactId>
<version>0.5.0-SNAPSHOT</version>
<name>cleartk-syntax</name>
...
<dependencies>
...
<dependency>
<groupId>org.cleartk</groupId>
<artifactId>cleartk-token</artifactId>
<version>0.7.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)
如果我mvn compile使用maven 2 运行,我会收到以下错误:
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.
Missing:
----------
1) org.cleartk:cleartk-token:test-jar:tests:0.7.0-SNAPSHOT
Run Code Online (Sandbox Code Playgroud)
如果我使用maven 3我收到错误:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.654s
[INFO] Finished at: Mon Jan 24 21:19:17 CET 2011
[INFO] Final Memory: 16M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute …Run Code Online (Sandbox Code Playgroud) 我发现自己使用了很多嵌套映射,例如Map [Int,Map [String,Set [String]]],我希望在访问新密钥时自动创建新的地图,集等.例如以下内容:
val m = ...
m(1992)("foo") += "bar"
Run Code Online (Sandbox Code Playgroud)
请注意,如果我不需要,我不想在这里使用getOrElseUpdate,因为当你有嵌套的地图并且隐藏代码中实际发生的事情时,它会变得非常冗长:
m.getOrElseUpdate(1992, Map[String, Set[String]]()).getOrElseUpdate("foo", Set[String]()) ++= "bar"
Run Code Online (Sandbox Code Playgroud)
所以我重写了HashMap的"默认"方法.我尝试了两种方法,但都没有完全令人满意.我的第一个解决方案是编写一个创建地图的方法,但是当我声明变量或事情不起作用时,似乎我仍然必须指定完整的嵌套Map类型:
scala> def defaultingMap[K, V](defaultValue: => V): Map[K, V] = new HashMap[K, V] { | override def default(key: K) = {
| val result = defaultValue
| this(key) = result
| result
| }
| }
defaultingMap: [K,V](defaultValue: => V)scala.collection.mutable.Map[K,V]
scala> val m: Map[Int, Map[String, Set[String]]] = defaultingMap(defaultingMap(Set[String]()))
m: scala.collection.mutable.Map[Int,scala.collection.mutable.Map[String,scala.collection.mutable.Set[String]]] = Map()
scala> m(1992)("foo") += "bar"; println(m)
Map(1992 -> Map(foo -> Set(bar))) …Run Code Online (Sandbox Code Playgroud) 因此,在阅读这个问题时,有人指出,而不是程序代码:
def expand(exp: String, replacements: Traversable[(String, String)]): String = {
var result = exp
for ((oldS, newS) <- replacements)
result = result.replace(oldS, newS)
result
}
Run Code Online (Sandbox Code Playgroud)
您可以编写以下功能代码:
def expand(exp: String, replacements: Traversable[(String, String)]): String = {
replacements.foldLeft(exp){
case (result, (oldS, newS)) => result.replace(oldS, newS)
}
}
Run Code Online (Sandbox Code Playgroud)
我几乎肯定会写第一个版本,因为熟悉程序或功能样式的编码人员可以轻松阅读和理解它,而只有熟悉功能样式的编码人员才能轻松阅读和理解第二个版本.
但暂时将可读性放在一边,有没有foldLeft比程序版更好的选择呢?我可能认为它会更有效率,但事实证明,foldLeft的实现实际上只是上面的过程代码.那么它只是一种风格选择,还是有充分的理由使用一个版本或另一个版本?
编辑:为了清楚,我不是在询问其他功能foldLeft.我与使用非常开心foreach,map,filter等,这些都很好地映射到换内涵.
答:实际上有两个很好的答案在这里(提供delnan和戴夫·格里菲斯),即使我只能接受一个:
foldLeft是因为还有其他优化,例如使用一个比for循环更快的while循环.fold如果它被添加到常规的集合,因为那样会使平行收藏琐碎的转变.我们有许多不在任何地方托管的第三方依赖项.对于其中的每一个,我们都有一个jar文件,我们希望能够安装和/或部署到我们的存储库.一些jar文件有自己的依赖项,我们还需要声明这些.
我们为每个声明groupId,artifactId,依赖项等的jar文件制作了pom.xml文件.这些pom.xml文件都有一个共同的父pom,它声明了一些常见的信息(例如<repositories>和<distributionManagement>).
我想能够安装或部署这些依赖与作为简单的东西mvn install和mvn deploy(或者mvn install:install-file和mvn deploy:deploy-file),并拥有所有这些命令的必要的属性(artifactId,repositoryId,等)从pom.xml的文件中读取.
为了使这个工作,至少为了部署,我尝试将以下内容放在我的父pom中:
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
<configuration>
<file>${jarfile}</file>
<pomFile>pom.xml</pomFile>
<repositoryId>our-id</repositoryId>
<url>our-url</url>
</configuration>
</plugin>
</plugins>
</build>
Run Code Online (Sandbox Code Playgroud)
然后让每个子poms定义jarfile属性.这允许我运行mvn deploy:deploy-file以部署所有子pom工件.据推测,我可以做类似的事情mvn install:install-file去上班.
但是使用这种方法,我无法释放父pom(我必须这么做,因为孩子poms依赖它),如果我尝试mvn release:perform使用父pom,我会得到如下错误:
Cannot override read-only parameter: pomFile
Run Code Online (Sandbox Code Playgroud)
我觉得我可能会以错误的方式解决这个问题.我真正想做的就是:
mvn install或mvn deploy不必指定所有那些复杂的命令行属性的东西我怎样才能做到最好?
编辑:制造这上面清晰的理想,我想能够运行一样简单的东西mvn install或者mvn deploy和没有指定命令行上的属性.
我有一个来自非常大的文件的行的迭代器,当我移动时需要将它们放入组中.我知道每个组的结束位置,因为每个组的最后一行都有一个标记值.所以基本上我想写一个函数,它接受一个迭代器和一个sentinel值,并返回一个组的迭代器,每个组都由sentinel值终止.就像是:
scala> groups("abc.defg.hi.jklmn.".iterator, '.')
res1: Iterator[Seq[Char]] = non-empty iterator
scala> groups("abc.defg.hi.jklmn.".iterator, '.').toList
res19: List[Seq[Char]] = List(List(a, b, c, .), List(d, e, f, g, .), List(h, i, .), List(j, k, l, m, n, .))
Run Code Online (Sandbox Code Playgroud)
请注意,我希望每个组的末尾都包含标记项.这是我目前的解决方案:
def groups[T](iter: Iterator[T], sentinel: T) = new Iterator[Seq[T]] {
def hasNext = iter.hasNext
def next = iter.takeWhile(_ != sentinel).toList ++ List(sentinel)
}
Run Code Online (Sandbox Code Playgroud)
我认为这会有效,我想这很好,但每次都要重新添加哨兵给我一个代码味道.有一个更好的方法吗?
我写了一些简单的scala脚本,最后以简单的模式匹配开头,args如:
val Array(path, foo, whatever) = args
// .. rest of the script uses "path", "foo", etc.
Run Code Online (Sandbox Code Playgroud)
当然,如果我提供了错误数量的参数,我会得到一个难以理解的错误:
scala.MatchError: [Ljava.lang.String;@7786df0f
at Main$$anon$1.<init>(FollowUsers.scala:5)
...
Run Code Online (Sandbox Code Playgroud)
是否有一种简单的方法可以提供更有用的错误消息?我目前的解决方法是执行以下操作:
args match {
case Array(path, foo, whatever) => someFunction(path, foo, whatever)
case _ => System.err.println("usage: path foo whatever")
}
def someFunction(path: String, foo: String, whatever: String) = {
// .. rest of the script uses "path", "foo", etc.
}
Run Code Online (Sandbox Code Playgroud)
但是,由于必须定义一个完整的其他功能,并且必须在很多地方重复"路径","foo"和"无论什么",这感觉就像很多样板.有没有更好的办法?我想我可能会丢失函数并将正文放入匹配语句中,但这对我来说似乎不太可读.
我知道我可以使用众多命令行参数解析包中的一个,但我真的在寻找一些非常轻量级的东西,我不需要添加依赖项并修改我的类路径.
我正在尝试实现默认值映射,并且我希望过滤器,映射等等,DefaultingMap以便DefaultingMap尽可能地生成.这是我最初的实现:
class DefaultingMap[K, V](defaultValue: => V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap[K, V](defaultValue)
override def default(key: K): V = {
val result = this.defaultValue
this(key) = result
result
}
}
Run Code Online (Sandbox Code Playgroud)
我DefaultingMap使用时会得到类型的对象filter,但是当我使用时却没有map:
scala> val counter = new DefaultingMap[Char, Int](0)
counter: DefaultingMap[Char,Int] = Map()
scala> for (c <- "ababcbbb") counter(c) += 1
scala> counter.filter{case (k, v) => v > 1}
res1: …Run Code Online (Sandbox Code Playgroud)