我有以下代码。我已经开始学习scala所以可能会有更好的方法来做这些东西,但我想学习它的每一点。如果代码看起来很幼稚,请耐心等待。
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
,我就不必匹配一次从map中检索值。这种理解是否正确如果不是,请告诉我这里出了什么问题。
答案 0 :(得分:2)
如果我们查看scala.collection.mutable.Map.get()的scaladoc,方法签名将被描述为:
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中,由于模式匹配,通常可以避免显式强制转换。例如,如果您想要明确地从Product
打开Option[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)
答案 1 :(得分:0)
尝试productMap.get(name).get()。asInstanceOf [产品] 或者只是productMap(name).asInstanceOf [Product]