2011-01-27 303 views
5

我正在將一些Java代碼轉換爲Scala,試圖儘可能使代碼儘量慣用。因此,我現在有一些代碼使用Options而不是可以爲空的值,我想知道事情是否是scala'ish,或者我是否錯了。那麼,你們可以批評下面的代碼片段嗎?在Scala中使用選項的習慣使用方式

中,我專門找了反饋的領域有:

  • 使用一個同伴對象作爲一個工廠,給這取決於我們是否想通過期權或者行2,2選項:是String構造罰款,還是我們應該總是揭露這是一個選項的事實?
  • 前提條件的使用:是否有更好的方法來斷言alpha3Code和name是必需的事實,並且必須爲alpha2Code傳遞非null選項? (我正在使用Guava作爲字符串utils,因爲我在Scala API中沒有找到任何東西)
  • hashCode,equals和toString的實現。 equals和toString再次委託給Guava,而equals使用模式匹配。有沒有更加糟糕的方式?
  • 我知道我可以使用Case類,它會創建默認實現,但我最感興趣的是學習如何實現那些案例類不能使用的情況。

非常感謝!

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() 
} 
+1

的「帽子戲法」,以使用選項是隻使用選項,並迫使消費者做同樣的;-)當然這不是在處理Java(ick!)時總是很實用。歡迎來到SO。 – 2011-01-28 00:52:22

+0

我不認爲需要(alpha2Code!= null)可能會失敗,因爲alpha2Code是一個選項 – Azzie 2014-09-25 21:07:01

回答

4

我想你應該在工廠方法中只公開Option[String]。例如,作爲你圖書館的用戶,我也會問自己,問我應該使用哪種工廠方法。而且很可能我會使用Option。

斯卡拉爲我們提供了足夠的工具,讓我們的生活更輕鬆。例如,你可以使用默認的選項是這樣的:

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更加牢固和明確的。

+3

實際上,有一種更簡單的方法來包裝一個對象在`Option`中,使'null`值變爲`None`: `Option(t)`(而不是`Some(t)`) – Madoc 2011-01-27 23:45:59

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)) 

雖然不一定是改進。

A StringhashCode,所以我不明白你爲什麼要調用另一種方法來生成哈希碼,而不是僅僅調用alpha3Code.hashCode。不過,我認爲在Scala API中有一些東西。不確定。

equals代碼應該有一個canEqual方法,除非你讓你的類sealedfinal。模式匹配是相當多的方式做到這一點,雖然你可以寫像這樣給出的提取存在:

case Language(_, `alpha3Code`, _) => true 

但是你寫的方式是相當多的,通常編寫方式。

-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() 
} 

Guava docs