我必須像這樣處理在庫中定義的類(無法更改):
trait parent {
def joke: String
}
trait accountant {
def number: Int
}
case class Person1(val joke: String, val number: Int, val age: Int, val isSmart: Boolean) extends parent with accountant
case class Person2(val joke: String, val number: Int, val age: Int, val isStrong: Boolean) extends parent with accountant
case class Person3(val joke: String, val age: Int, val isTall: Boolean) extends parent
我需要根據欄位值進行一些計算,并發出這樣的 API 中定義的信號(無法更改):
trait MySignal
case class GotPerson1() extends MySignal
case class GotPerson2() extends MySignal
請記住,這是一個按比例縮小的示例,大約有 10 個不同PersonX的 ,對這些 Person 型別的某些對/組要進行一些通用計算:
class DoingWork(message: parent) {
type WithAge = {def age: Int, def number: Int}
def dispatcher(msg: parent) = {
msg match {
case something: Person1 => doSomeMapping(something)
case something: Person2 => doSomeMapping(something)
case something: Person3 => doSomethingElse(something)
}
}
def doSomeMapping(msg: WithAge): MySignal = {
// do some common cal based on WithAge fields
if(msg.number > 10 && msg.isInstanceOf[Person1]) GotPerson1()
else if(msg.number > 10 && msg.isInstanceOf[Person2]) GotPerson2()
else throw new RuntimeException()
}
def doSomethingElse(msg: Person3): Unit = println("blah")
}
為了避免復制普通計算的代碼,我介紹了type WithAge但是因為我必須根據型別發出不同的信號,所以我必須測驗型別。
我怎樣才能避免isInstanceOf測驗doSomeMapping?
我可以將MySignal子型別作為引數傳入doSomeMapping以允許函式實體化它嗎?
uj5u.com熱心網友回復:
你可以引入一個型別類:
trait SignalProvider[T] {
def signal: MySignal
}
object SignalProvider {
// instances for Person1 and Person2
implicit val person1Instance: SignalProvider[Person1] =
new SignalProvider[Person1] {
def signal: MySignal = GotPerson1()
}
implicit val person2Instance: SignalProvider[Person2] =
new SignalProvider[Person2] {
def signal: MySignal = GotPerson2()
}
}
那么這將起作用:
def dispatcher(msg: parent) = {
msg match {
case something: Person1 => doSomeMapping[Person1](something)
case something: Person2 => doSomeMapping[Person2](something)
case something: Person3 => doSomethingElse(something)
}
}
def doSomeMapping[T <: WithAge](msg: WithAge)(implicit s: SignalProvider[T]): MySignal = {
// do some common cal based on WithAge fields
if(msg.number > 10) s.signal
else throw new RuntimeException()
}
請注意,您必須在呼叫時顯式提供型別引數doSomeMapping- 如果您只是撰寫,編譯器將無法確定要使用哪個型別類實體doSomeMapping(something)(并且編譯將因“模糊隱含值”而失敗)。
更新:替代解決方案
雖然上面可能很花哨,但我不確定我是否會選擇這個簡單的解決方案,如果它是我的代碼,它不涉及隱式和型別類等概念(這可能還取決于還有誰需要使用該代碼以及他們對這些概念的熟悉程度):
def dispatcher(msg: parent) = {
msg match {
case something: Person1 => doSomeMapping(something, GotPerson1())
case something: Person2 => doSomeMapping(something, GotPerson2())
case something: Person3 => doSomethingElse(something)
}
}
// note that signal is passed by name, so no instance will be created
// if one ends up in the else-branch that throws the exception:
def doSomeMapping(msg: WithAge, signal: => MySignal): MySignal = {
// do some common cal based on WithAge fields
if(msg.number > 10) signal
else throw new RuntimeException()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/504772.html
標籤:斯卡拉
上一篇:Oracle 表空間常用操作
