这是我一段时间都想知道的事情.我看到这种模式很多:
if (pf.isDefinedAt(in)) pf(in)
Run Code Online (Sandbox Code Playgroud)
通过将其分解为两个单独的调用,在#isDefinedAt中计算的所有模式也将在#apply中进行评估.例如:
object Ex1 {
def unapply(in: Int) : Option[String] = {
println("Ex1")
if (in == 1) Some("1") else None
}
}
object Ex2 {
def unapply(in: Int) : Option[String] = {
println("Ex2")
if (in == 2) Some("2") else None
}
}
val pf : PartialFunction[Int,String] = {
case Ex1(result) => result
case Ex2(result) => result
}
val in = 2
if (pf.isDefinedAt(in)) pf(in)
Run Code Online (Sandbox Code Playgroud)
哪个打印
Ex1
Ex2
Ex1
Ex2
res52: Any = 2
Run Code Online (Sandbox Code Playgroud)
在最坏的情况下,您的模式最后匹配,在调用PartialFunction时,您已经两次评估了模式/提取器.当匹配不仅仅是简单的类或列表模式匹配的自定义提取器时,这可能会变得低效(例如,如果您有一个解析XML文档并返回一些值对象的提取器)
PartialFunction#lift遭受同样的双重评估:
scala> pf.lift(2) …Run Code Online (Sandbox Code Playgroud) scala> class Foo[T <: Comparable[T]](val x : T)
defined class Foo
scala> (3: Int).asInstanceOf[Comparable[Int]]
res60: java.lang.Comparable[Int] = 3
scala> new Foo(3)
<console>:13: error: inferred type arguments [Int] do not conform to class Foo's type parameter bounds [T <: java.lang.Comparable[T]]
new Foo(3)
^
Run Code Online (Sandbox Code Playgroud)
第二个表达式是类型擦除的结果吗?
我将如何定义Foo以便我可以使用Int对其进行参数化,但仍然能够使用其实例变量执行某些排序行为?
即使Box和Option monad普遍存在,我们仍然需要在这里和那里检查空值.到目前为止,我提出的最好的方法是使用Box#!! 方法:
(Box !! possiblyNull).map(_.toString).openOr("")
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?我尝试使用Box的apply方法:
Box(possiblyNull).map(_.toString).openOr("")
Run Code Online (Sandbox Code Playgroud)
但编译器抱怨对重载定义的模糊引用,特别是:
[InType,OutType](value: InType)
(pf: PartialFunction[InType,OutType])net.liftweb.common.Box[OutType]
Run Code Online (Sandbox Code Playgroud)
我不确定为什么会发生这种情况,但我希望有一种更简洁,更简洁的方式来说"给我这个字符串的价值,或者只是".我正在考虑使用tryo,但认为这很浪费可以避免的例外情况.
在Rails中,可以使用:
returning Person.create do |p|
p.first_name = "Collin"
p.last_name = "VanDyck"
end
Run Code Online (Sandbox Code Playgroud)
避免必须这样做:
person = Person.create
person.first_name = "Collin"
person.last_name = "VanDyck"
person
Run Code Online (Sandbox Code Playgroud)
我认为前一种方式更清洁,重复性更低.我发现自己在Scala项目中创建了这个方法:
def returning[T](value: T)(fn: (T) => Unit) : T = {
fn(value)
value
}
Run Code Online (Sandbox Code Playgroud)
我知道由于对象倾向于不可变,它的实用性有限,但是例如使用Lift,在Mapper类上使用这种方法效果很好.
是否有Scala模拟用于"返回",我不知道?或者,在Scala中有类似的方法可以做到这一点吗?
这是使用Scala 2.8 Actors.我有一个可以并行化的长期工作.它包括大约65万单位的工作.我将它划分为2600个不同的单独子任务,并为每个子任务创建一个新的actor:
actor {
val range = (0L to total by limit)
val latch = new CountDownLatch(range.length)
range.foreach { offset =>
actor {
doExpensiveStuff(offset,limit)
latch.countDown
}
}
latch.await
}
Run Code Online (Sandbox Code Playgroud)
这种方法效果很好,但总体上需要2 + h才能完成.问题在于,与此同时,我创建的任何其他演员都做正常的任务似乎被最初的2600名演员挨饿,这些演员也耐心地等待他们的时间在一个线程上运行但是等待的时间比任何新的演员要长.一起来.
我怎么能避免这种饥饿呢?
初步想法:
UPDATE
有些人质疑Actors的使用,特别是因为消息传递能力没有在工作者中使用.我假设Actor是一个非常轻量级的抽象,围绕一个ThreadPool处于或接近相同的性能级别,只需手动编写基于ThreadPool的执行.所以我写了一个基准:
import testing._
import java.util.concurrent._
import actors.Futures._
val count = 100000
val poolSize = 4
val numRuns = 100
val ActorTest = new Benchmark {
def run = {
(1 to count).map(i => future {
i * i
}).foreach(_())
}
}
val …Run Code Online (Sandbox Code Playgroud) 我正在努力解决我在作业上遇到的问题.
如何在Java中检查值是否在一个范围内,例如1≤值≤31,而不使用if,switch或任何其他控制结构?
真的很难找出用一个代表一组具体类型的类扩展不可变集合.我这样做是为了尝试创建一个不错的DSL.
我想要一个类Thing,当你将'things'加在一起时,你得到一个ThingSet对象,它扩展了Set.
class Thing(val name:String){
def +(other: Thing):ThingSet = new ThingSet() + other
}
Run Code Online (Sandbox Code Playgroud)
我只是无法弄清楚如何制作ThingSet对象.我知道我需要混合GenericSetTemplate,SetLike等特性.但我无法使它工作.
请问,任何人都可以给我一些指示,因为我找不到任何明确的东西可以借鉴.我试过看BitSet和HashSet实现,但迷路了.
我的应用程序最终通过Actors进行大量后台处理,特别是加载Mapper实例,然后对它们进行一些工作.这是非常重复的,我想在我的Actor代码中缓存一些这些查找.
我通常会使用ThreadLocal.但是,由于线程初始化是由Actor线程池处理的,所以它似乎是唯一一个初始化并随后清除ThreadLocal的地方是在actor的PartialFunction中接收传入的消息.
我现在正在做的是在我的Actor中创建另一个方法,如下所示:
override def aroundUpdates[T](fn: => T) : T = {
clientCache.init {
fn
}
}
Run Code Online (Sandbox Code Playgroud)
凡init方法处理以清除ThreadLocal的finally块.我不喜欢这种方法,因为aroundUpdates只存在于设置缓存的目的,它闻起来像代码味道.
有一个更好的方法吗?