2016-05-12 19 views
1

我有以下代碼。我已經開始學習Scala,所以可能會有更好的方法來做這些事情,但我想學習它的每一點。如果代碼看起來很幼稚,請耐心等待。scala.Some不能轉換爲自定義對象

class ColaProduct() extends Product{ 
    override def productName = "Cola" 
    override def productDetails = "Chilled Cola" 
    override def toString(): String = super.toString() 
    } 

    class MilkProduct() extends Product{ 
    override def productName = "Milk" 
    override def productDetails = "Healthy Milk" 
    override def toString(): String = super.toString() 
    } 

    trait Machine { 
    private val productMap = scala.collection.mutable.Map[String, Product]() 
    def addProduct(product: Product): Unit ={ 
     productMap += product.productName.toString -> product 
    } 
    def checkAvl(name :String): Product ={ 
     if(productMap contains(name)){ 
     return productMap.get(name).asInstanceOf[Product] 
     } else null 
    } 
    def process(name :String) 
    } 

    class VendingMachineImpl() extends Machine{ 
    override def process(name : String): Unit ={ 
     val product = checkAvl(name) 
     if(null !=product){ 
     print("Got you :"+product.toString()) 
     } 
    } 
    } 

    trait Product { 

    private val defaultString: String = "Default" 
    def productName = defaultString 
    def productDetails = defaultString 

    override def toString(): String = { 
     return productName + " || " + productDetails 
    } 
    } 

    def main(args : Array[String]): Unit ={ 
    val vendingMachineImpl = new VendingMachineImpl() 
    vendingMachineImpl.addProduct(new ColaProduct) 
    vendingMachineImpl.addProduct(new MilkProduct) 

    vendingMachineImpl.process("Cola") 
    } 

例外:

Exception in thread "main" java.lang.ClassCastException: scala.Some cannot be cast to Product 
    at vendingMachine$Machine$class.checkAvl(vendingMachine.scala:27) 
    at vendingMachine$vendingMachineImpl.checkAvl(vendingMachine.scala:33) 
    at vendingMachine$vendingMachineImpl.process(vendingMachine.scala:35) 
    at vendingMachine$.main(vendingMachine.scala:47) 

我相信是有一次我與指定類型定義map我沒有一次匹配從地圖檢索值。如果不是,請讓我知道這裏出了什麼問題,這種理解是否正確?

回答

2

如果我們看一下scaladoc爲scala.collection.mutable.Map.get(),方法簽名描述如:

abstract def get(key: A): Option[B] 

該方法返回類型爲Option的值;如果您嘗試將其轉換爲某種不相關的類型,您將得到ClassCastException,與其他任何不兼容的類型一樣。如果你想有一個產品,你需要:

  • 檢查Option不是空
  • 拆開包裝內部包含

產品下面是做這件事的一種方式(不改變其他地區的代碼):

trait Machine { 
    // Notes: 
    // - no need to use 'return' keyword 
    // - It's good practice in Scala not to return null: use Option for optional values 
    def checkAvl(name :String): Option[Product] = 
    productMap.get(name) 
} 

class VendingMachineImpl() extends Machine{ 
    override def process(name : String): Unit ={ 
    val product = checkAvl(name) 
    // Think of Option as a collection containing 0 or 1 element: you can use 
    // foreach, map, etc. 
    // Also, string interpolation (with the s"" syntax) is cool. :-) 
    product.foreach(print(p => s"Got you : $p")) 
    } 
} 

編輯: 另外,在Scala中,由於模式匹配,通常可以避免顯式強制轉換。例如,如果你想明確地從Option[Product]解開的Product,你可以使用:

val opt: Option[Product] = ??? 
opt match { 
    // type-safe cast to type Some and deconstruction of the object (we get out the value 
    // wich was originally passed to the Some constructor) : 
    case Some(product) => print(s"Got you : $product") 
    // type-safe cast to type None : 
    case None => // do nothing 
} 

編輯2: 你還可以檢查出其他兩種方法用於從Map檢索值,取決於你正在嘗試做什麼:

val map: Map[String, String] = Map("k1" -> "v1", "k2" -> "v2") 

// getOrElse (using a default value) 
map.getOrElse("k1", "default") // returns "v1" 
map.getOrElse("foobar", "default") // returns "default" 

// apply (implementation-dependent, but fails fast by default) 
map("k1") // returns "v1" 
map("foobar") // throws a NoSuchElementException (it can be different for other Map 
       // implementations, but it's the default behavior) 
+0

所以如果我正確地理解它總是地圖給我一個選項[T],所以它不是強制性的指定地圖將包含的類型。這只是從可讀性的角度來看? – Helios

+0

在JVM上實現的Scala與Java一樣具有類型擦除功能:在運行時,「Option」只是一個「Option」。然而,在編譯時,知道你有一個'Option [Product]'是非常有用的(它會幫助編譯器爲你捕獲許多可能的錯誤)。如果你有'Map [String,Product]',如果你沒有做任何奇怪的事情,你可以保證'Map.get(String)'將返回一個'Option [Product]'而不是'Option [SomeOtherType]',這很好知道(並且會幫助編譯器幫助你)。 –

+0

此外,我編輯我的答案與其他可能性,以獲得從'地圖'的值。 –

0

嘗試productMap.get(名)獲得()。asInstanceOf [產品] 或只是productMap(名稱).asInstanceOf [產品]

相關問題