Я часто - написание кода, которое сравнивает два объекта и производит значение на основе того, являются ли они тем же, или отличающийся, на основе того, как они отличаются.
Таким образом, я мог бы записать:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) => "b"
case (None, Some(value)) => "b"
case _ = > "c"
}
Те 2-е и 3-и случаи являются тем же действительно, таким образом, я пытался писать:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) || (None, Some(value)) => "b"
case _ = > "c"
}
Но никакая удача.
Я встречаюсь с этой проблемой в нескольких местах, и это - просто определенный пример, более общий шаблон, у меня есть две вещи, и я хочу знать, встречают ли один и только один из них некоторый предикат, таким образом, я хотел бы записать что-то вроде этого:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
Таким образом, идея здесь состоит в том, что OneAndOnlyOne может быть настроен с утвержденным (isDefined в этом случае), и можно использовать его в нескольких местах.
Вышеупомянутое не работает вообще, начиная с назад, предикат должен быть передан в экстрактор, не возвращенный.
Как насчет чего-то вроде этого?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
с:
class OneAndOnlyOne[T](predicate: T => Boolean) {
def unapply( pair: Pair[T,T] ): Option[T] = {
val (item1,item2) = pair
val v1 = predicate(item1)
val v2 = predicate(item2)
if ( v1 != v2 )
Some( if ( v1 ) item1 else item2 )
else
None
}
}
Но, это не компилирует.
Кто-либо может видеть способ заставить это решение работать? Или предложите другое решение? Я, вероятно, делаю это более сложным, чем это :)
Если вы должны поддерживать произвольные предикаты, вы можете извлечь из этого (который основан на IDEA Daniel ):
List(v1, v2) filter (_ %2 == 0) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
Определение функции:
def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R =
p(List((values filter f) :_* ))
Теперь вы можете использовать это:
filteredMatch(v1,v2)(_ %2 == 0){
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
Я не так уверен, если это хорошая идея (то есть читаемая). Но аккуратные упражнения тем не менее.
Было бы здорово, если бы вы могли совпадать с корпусами: Case (значение1, значение2) => ...
вместо списков.
Я думаю, что вы задаете два несколько разных вопроса.
Один вопрос: как использовать «или» в выключателях. || не работает; |. делает. И вы не можете использовать переменные в этом случае (потому что в целом они могут сопоставить различные типы, что делает тип запутанности). Итак:
def matcher[T](a: (T,T)) = {
a match {
case (Some(x),Some(y)) => "both"
case (Some(_),None) | (None,Some(_)) => "either"
case _ => "none"
}
}
Другой вопрос - это то, как избежать необходимости делать это снова и снова, особенно если вы хотите получить по стоимости в кортеже. Я реализовал эту версию для опции, но вы можете использовать развернутый кортеж и логию.
Один из трюков для достижения этого является то, что для предварительного взаимодействия значений, прежде чем начать совпадать на нем, а затем использовать свои собственные сопоставленные конструи, которые вы хотите. Например,
class DiOption[+T] {
def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
t2 match {
case (Some(x),Some(y)) => Both(x,y)
case (Some(x),None) => OneOf(x)
case (None,Some(y)) => OneOf(y)
case _ => Neither()
}
}
// Example usage
val a = (Some("This"),None)
a trinary match {
case Both(s,t) => "Both"
case OneOf(s) => "Just one"
case _ => "Nothing"
}
Как насчет этого:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def m(v1: Any,v2: Any) = (v1,v2) match {
| case (Some(x),Some(y)) => "a"
| case (Some(_),None) | (None,Some(_)) => "b"
| case _ => "c"
| }
m: (v1: Any,v2: Any)java.lang.String
scala> m(Some(1),Some(2))
res0: java.lang.String = a
scala> m(Some(1),None)
res1: java.lang.String = b
scala> m(None,None)
res2: java.lang.String = c
scala>
Как насчет использования начального состояния...
int enter_dblquotes = 0; %x DBLQUOTES %% \" { BEGIN(DBLQUOTES); enter_dblquotes++; } <DBLQUOTES>*\" { if (enter_dblquotes){ handle_this_dblquotes(yytext); BEGIN(INITIAL); /* revert back to normal */ enter_dblquotes--; } } ...more rules follow...
Он был аналогичен этому эффекту (flex использует % s
или % x
для указания ожидаемого состояния. Когда вход Flex обнаруживает кавычку, он переключается в другое состояние, а затем продолжает лексировать до тех пор, пока не достигнет другой кавычки, в которой он возвращается в нормальное состояние.
Sinkhole предприятия:
1: прочитайте, что доступ к базе данных должен быть на отдельном уровне
2: Эй, у нас есть уровень базы данных.
2 (b) Эй, у нас даже есть делегированный слой, чтобы абстрагироваться от нашей базы данных.
3: Примените закон утечек абстракций -i.e, так как в делегатах есть методы, которые получают вещи, просто предположим, что они там, чтобы использовать без мысли о последствиях - как в вызове «getPurchaseOrder ()» 10 раз подряд на странице, даже если getPurchaseOrder () является методом, который оборачивается 5 отдельных вызовов базы данных.
4: Сидите и наслаждайтесь своими веб-страницами, которые загружаются с 100 отдельными вызовами базы данных (к сожалению, не преувеличение).
Не уверен, что я бы назвал это антиобразцом? Может быть «Слои не свободны»?
-121--4294089-Это можно сделать, если сначала определить его как значение:
val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case MyValThatIsCapitalized(value) => "b"
case _ = > "c"
}
Имя значения, содержащего объект-экстрактор, должно быть оприходовано.
на Scala 2.8:
val result = List(v1,v2).flatten match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
на Scala 2.7, однако, вам нужен подсказку типа, чтобы сделать его работать. Таким образом, предположение значение
INT
, затем: INT
, например:
val result = (List(v1,v2).flatten : List[Int]) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
Забавная вещь в том, что я неправильно прочитал «первым» как «Список» на Mitch Blevins Ответ, и это дало мне эту идею. : -)