我试图找出scala方式来实现我在java中一直做的事情。 在java中我会让snarf_image(下面)在满足if条件时返回null,否则返回bArray。 scala的方法是什么?这段代码甚至无法编译,我无法找到正确的方法 - 我确信我的想法已经完成。
def snarf_image ( sUrl : String ) : Array[Byte] = {
val bis = new BufferedInputStream(new URL(sUrl.replace(" ", "%20")).openStream())
val bArray = Stream.continually(bis.read).takeWhile(-1 !=).map(_.toByte).toArray
val img = ImageProcessing.ArrayToImage(bArray)
if ( img.getHeight < 100 || img.getWidth < 100 ) {
Empty
} else {
bArray
}
}
对于记录我使用电梯(因此使用空)但我很确定这更像是一个scala问题。
答案 0 :(得分:8)
有时候,如果要返回null(在Java中),可以使用Option
。
我没有编译它,但它应该可以工作。
def snarf_image ( sUrl : String ) : Option[Array[Byte]] = {
val bis = new BufferedInputStream(new URL(sUrl.replace(" ", "%20")).openStream())
val bArray = Stream.continually(bis.read).takeWhile(-1 !=).map(_.toByte).toArray
val img = ImageProcessing.ArrayToImage(bArray)
if ( img.getHeight < 100 || img.getWidth < 100 ) {
None
} else {
Some(bArray)
}
}
答案 1 :(得分:4)
TLDR:有很多选项可供使用:Option,Box,Either,Try甚至Future(还有更多可以在不同的库中找到),可能你会对Option有好处强>
首先,您可以使用空集合而不是null - 它不仅适用于Scala,而且适用于许多其他语言,包括Java和C#:
def snarf_image ( sUrl : String ) : Array[Byte] = {
// ...
if ( img.getHeight < 100 || img.getWidth < 100 ) {
Array.empty[Byte]
} else {
bArray
}
}
当然,这可能无法让您远离惊喜,因为您可能会意外忘记检查收集是否空虚,但您更有可能会因为null而获得巨大的惊喜。
另见Is it better to return null or empty collection?
接下来是Option。
当你有某些东西(Some
)或没有东西(None
)时使用选项,而你不关心原因(只有一个原因或无关紧要)。
该选项不是scala发明(我已经看过ML语言,在Haskell中它被称为Maybe,它甚至是comes to the std lib in java 8和available to use in earlier java versions as a guava part)。
它在标准库中广泛使用,您可能会在许多第三方库中看到它。典型的例子可以是从Map中检索,当没有这样的密钥时 - 选项强调Map不能包含这样的密钥,所以你必须要么 - 处理丢失密钥的可能性或进一步传播它。
val xys = Map(1 -> "foo", 2 -> "bar")
xys.get(3)
// Option[String] = None
xys.get(1)
// Option[String] = Some(foo)
xys.get(2).toUpperCase
// cannot operate directly on Option -- has to unwrap it first:
// error: value toUpperCase is not a member of Option[String]
当您想知道为什么 或时,当您有两种可能性(不仅是成功/失败)或时,请使用或使用旧版本的scala(2.10之前)
它与Option完全相同,不仅用于Scala,还用于其他一些语言(例如已经提到过的Haskell)。除了可疑的区别 - 要么不是Scala中的monad,主要区别在于你没有 empty 元素,你有 right 或 left < / em>的。这是一种比Option不太常用的方式,因为它不能立即清楚什么应该是正确的,应该留下什么,但是the common convention is to use Right for the successful value and Left for a faulty path(通常它包含Throwable对象,并解释出了什么问题)。 Either主要是由Try发出的,这不是fabulos和originally born in Twitter(最大和最早的Scala采用者之一)。
在scala 2.10+中使用try成功的值/失败原因(或者2.9.3,因为它被反向移植)
从名为“成功与失败”的案例开始,它更方便一些。
来自official doc的例子(顺便说一句,这很好):
导入scala.util。{尝试,成功,失败}
def divide: Try[Int] = {
val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt)
val divisor = Try(Console.readLine("Enter an Int that you'd like to divide by:\n").toInt)
val problem = dividend.flatMap(x => divisor.map(y => x/y))
problem match {
case Success(v) =>
println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
Success(v)
case Failure(e) =>
println("You must've divided by zero or entered something that's not an Int. Try again!")
println("Info from the exception: " + e.getMessage)
divide
}
}
当你的选项在时空连续体上被分割时使用未来:现在它是空的,但是几秒钟之前它已经完成(但反之亦然 - 未来一个实现过程)。
未来在Scala中是新的,就像Try一样,就像试试它从Twitter的路径一样。它在并发代码中使用,您希望将某些工作发送到后台,并在稍后等待结果或在完成时调用回调。尝试作为一个明确的结果 - 未来成功完成或异常结束(被捕异常)。
请注意,Future(Scalaz,Unfiltered,Twitter,Akka)有很多实现 - 它们可能会与scala.actors.Future
统一起来
进一步阅读brilliant overview of scala Futures/Promises。
Box应该用于Lift生态系统,基本上是类固醇的选项,作为空/全路径。
Or and Every。或模仿Either和Box,Every用于收集许多错误。
Validation。在Scalaz库中使用。