![](/img/trans.png)
[英]What's the best way to match strings in a file to case class in Scala?
[英]What's the best way to extract a value from a scala case class?
提取我在案例類中保存的值的最佳和/或最簡單的方法是什么?
以下面的代碼為例:
abstract class Something
case class Foo(input: Int) extends Something
case class Bar(input: Double) extends Something
def someMethod(a: Something, b: Something) {
// code that extracts values goes here
}
someMethod(Foo(10), Foo(20))
someMethod(Bar(2.1), Bar(21.2))
當我按照它的定義調用方法時,我將如何從a
和b
獲取整數或雙精度本身?
請注意,兩個參數都在同一個等式中使用
如果類構造函數參數是val,那么只需調用:
a.input
b.input
您還可以在unapply
方法的幫助下使用提取器:
val Foo(val1) = a
val Bar(val2) = b
然后使用val1
和val2
更新
那么你應該在你的價值上使用模式匹配:
value match {
case Foo(val1) => val1
case Bar(val1) => val1
}
它就像val Foo(val1) = a
,在你的類中使用生成的unapply
方法(提取器),它也是一個表達式,所以你將結果賦給變量
如果您有多個參數,只需根據參數的數量更改PatMat構造,在您的情況下:
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), Foo(v2)) => (v1, v2) // or any other logic with values
case (Foo(v1), Bar(v2)) => // logic for this case
... // logic for other cases
}
參數越多,您應提供的案例就越多,但如果您不需要它們,則會出現空白案例
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), Foo(v2)) => (v1, v2) // or any other logic with values
case _ =>
}
在這種情況下,所有其他情況都將被忽略,而不是最佳選擇,因為結果類型將是不正確的。 你也可以黑人價值觀
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), _) => v1 // in such case you can work only with v1
... // logic for other cases
}
模式匹配的替代方法可以是重新定義您的類,如下所示:
trait Something[T]{
def input:T
}
case class Foo(input: Int) extends Something[Int]
case class Bar(input: Double) extends Something[Double]
然后, Something
任何實例都將公開input
屬性。 唯一可能的缺點是,當您訪問它時它將是通用類型。
在您的示例中, a
和b
都具有特定類型: Foo
和Bar
。 這就是為什么你可以簡單地訪問他們的字段,如下所示:
scala> a.input
res4: Int = 10
scala> b.input
res5: Double = 25.1
但是,如果您的值類型為Something
,那么您需要進行模式匹配:
val input = somethingOfTypeSomething match {
case Foo(input) => input
case Bar(input) => input
}
除了 在您的方法中 直接解決模式匹配問題之外,我將嘗試在這種情況下展示一種更復雜,通用和功能性的方法。 靜止模式匹配是最直接, 最簡單的答案!
如果您可以在界面中明確“認證” input
訪問器,則可以概括您使用Something
類的方式。
在代碼中,這轉換為
trait Something[T] {
def input: T
}
case class Foo(input: Int) extends Something[Int]
case class Bar(input: Double) extends Something[Double]
從這里你可以定義如何將你喜歡的任何功能“提升”到一個適用於Something
s的功能
假設您有兩個輸入方法(例如Ints
或Doubles
),並且您希望在一個案例類(即Foo
, Bar
)中對這些輸入進行操作
//this function lift your specific input method to one that takes Somethings
def liftSomething2[T, R](f: (T, T) => R): (Something[T], Something[T]) => R =
(a, b) => f(a.input, b.input)
讓我們來看一下:它需要一個函數
(T, T) => R
的類型的2個參數T
和結果R
並將其轉換為
(Something[T], Something[T]) => R
將Something
s作為參數。
例子
//lifts a function that sums ints
scala> val sumInts = liftSomething2[Int, Int](_ + _)
sumInts: (Something[Int], Something[Int]) => Int = <function2>
//lifts a function that multiplies ints
scala> val multInts = liftSomething2[Int, Int](_ * _)
multInts: (Something[Int], Something[Int]) => Int = <function2>
//lifts a function that divides doubles
scala> val divDbl = liftSomething2[Double, Double](_ / _)
divDbl: (Something[Double], Something[Double]) => Double = <function2>
//Now some test
scala> sumInts(Foo(1), Foo(2))
res2: Int = 3
scala> multInts(Foo(4), Foo(-3))
res3: Int = -12
scala> divDbl(Bar(20.0), Bar(3.0))
res4: Double = 6.666666666666667
//You can even complicate things a bit
scala> val stringApp = liftSomething2[Int, String](_.toString + _)
stringApp: (Something[Int], Something[Int]) => String = <function2>
scala> stringApp(Foo(1), Foo(2))
res5: String = 12
以上所有示例都提升了類型(T,T) => R
函數,但可以對所有需要的參數進行“提升”
//This takes three args of different types and returns another type
// the logic doesn't change
def liftSomething3[A,B,C,R](f: (A,B,C) => R): (Something[A], Something[B], Something[C]) => R =
(a,b,c) => f(a.input, b.input, c.input)
//sums to ints and divides by a double
scala> val sumDiv = liftSomething3[Int,Int,Double,Double]((i,j,d) => (i + j) / d)
sumDiv: (Something[Int], Something[Int], Something[Double]) => Double = <function3>
scala> sumDiv(Foo(5), Foo(30), Bar(4.2))
res7: Double = 8.333333333333332
到目前為止我們所看到的應該與類別理論概念有點相關,比如Applicative Functors和Comonads ,但我不是專家所以如果你覺得這種抽象是有用和有趣的,我鼓勵你自己搜索。
其他答案涵蓋了基本情景。 有一些有用的變化需要考慮。
構造函數模式
正如已經回答的那樣:
value match {
case Foo(x) => x
...
}
深度匹配
構造函數模式還支持深度匹配。 例如,在Foo中的Bar內提取x,深度為3級:
value match {
case Foo(y, Bar(x)) => x
...
}
變量綁定
如果要提取的值是另一個案例類中的實際案例類,則可以使用變量綁定。 例如,將整個Bar(x)提取到b中:
value match {
case Foo(y, b @ Bar(x)) => b
...
}
由M. Odersky,Spoon和Venners 編寫的Scala編程有很多關於案例類和模式匹配的章節,涵蓋了許多其他場景。 模式匹配是語言中非常豐富的一部分,值得投資。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.