我正在将一些Java代码转换为Scala,试图尽可能使代码成为惯用语。
所以,我现在有一些使用Options而不是可空值的代码,我想知道是不是scala'ish,或者我是不是错了。那么,你们可以批评下面的代码片段吗?
我专门寻找反馈的领域是:
非常感谢!
package com.sirika.openplacesearch.api.language
import com.google.common.base.Objects
import com.google.common.base.Strings
object Language {
def apply(name : String, alpha3Code : String, alpha2Code : Option[String]) = new Language(name, alpha3Code, alpha2Code)
def apply(name : String, alpha3Code : String, alpha2Code : String = null) = new Language(name, alpha3Code, Option(alpha2Code))
def unapply(l : Language) = Some(l.name, l.alpha3Code, l.alpha2Code )
}
class Language(val name : String, val alpha3Code : String, val alpha2Code : Option[String]) {
require(!Strings.isNullOrEmpty(alpha3Code))
require(!Strings.isNullOrEmpty(name))
require(alpha2Code != null)
override def hashCode(): Int = Objects.hashCode(alpha3Code)
override def equals(other: Any): Boolean = other match {
case that: Language => this.alpha3Code == that.alpha3Code
case _ => false
}
override def toString() : String = Objects.toStringHelper(this)
.add("name", name)
.add("alpha3", alpha3Code)
.add("alpha2", alpha2Code)
.toString()
}
答案 0 :(得分:4)
我认为你应该只在工厂方法中公开Option[String]
。例如,我作为您图书馆的用户,也会问自己问我应该使用哪种工厂方法。而且很可能我会使用Option。
Scala为我们提供了足够的工具,使我们的生活更轻松。例如,您可以使用默认选项,如下所示:
def apply(name: String, alpha3Code: String, alpha2Code: Option[String] = None) =
new Language(name, alpha3Code, alpha2Code)
如果我再次作为你的库的用户,想要每次只传递字符串而不将其包装在Some
中,我可以像这样编写自己的隐式转换:
implicit def anyToOption[T](t: T): Option[T] = Some(t)
甚至(如果我个人使用空值):
implicit def anyToOption[T](t: T): Option[T] =
if (t == null) None else Some(t)
但我相信,如果您强制执行选项,它将使您的API更加稳固和清晰。
答案 1 :(得分:4)
除非有充分的理由不这样做,否则你应该避免null
。事实上,你可以写下这个:
def apply(name : String, alpha3Code : String, alpha2Code : String) = new Language(name, alpha3Code, Option(alpha2Code))
def apply(name : String, alpha3Code : String) = new Language(name, alpha3Code, None)
前提条件很好。你可以这样写:
require(Option(alpha3Code) exists (_.nonEmpty))
require(Option(name) exists (_.nonEmpty))
但不一定是改进。
String
有hashCode
,所以我不明白你为什么要调用另一种方法来生成哈希码,而不是只调用alpha3Code.hashCode
。我确实认为Scala API中有一些东西。不确定。
equals
代码应采用canEqual
方法,除非您创建课程sealed
或final
。模式匹配几乎就是这样做的,尽管你可以这样写,因为存在一个提取器:
case Language(_, `alpha3Code`, _) => true
但你写它的方式几乎就是它通常写的方式。
答案 2 :(得分:-1)
我不喜欢选项 - 他们添加了一个间接级别,这在许多情况下是不必要的和令人困惑的。我更不喜欢空值,所以我理解通常使用选项是合理的。但是,您应该始终看看是否有更自然的方法来消除在界面中使用Option
。
默认参数或单独的重载通常是更好的选择。所以我会像这样重写你的代码:
package com.sirika.openplacesearch.api.language
import com.google.common.base.Strings
import com.google.common.base.Objects
object Language {
def apply(name : String, alpha3Code : String, alpha2Code : String) = new Language(name, alpha3Code, alpha2Code)
def apply(name : String, alpha3Code : String ) = new Language(name, alpha3Code)
def unapply(l : Language) = Some(l.name, l.alpha3Code, l.alpha2Code )
}
class Language private (val name : String, val alpha3Code : String, val alpha2Code : Option[String]) {
def this(name:String,alpha3Code: String ,alpha2Code:String) = this(name,alpha3Code,Option(alpha2Code))
def this(name:String,alpha3Code: String) = this(name,alpha3Code,None)
require(!Strings.isNullOrEmpty(alpha3Code))
require(!Strings.isNullOrEmpty(name))
override def hashCode = alpha3Code.hashCode
override def equals(other: Any) = other match {
case that: Language => this.alpha3Code == that.alpha3Code
case _ => false
}
override def toString = MoreObjects.toStringHelper(this)
.add("name", name)
.add("alpha3", alpha3Code)
.add("alpha2", alpha2Code)
.toString()
}