패턴 매칭 vs if-else
저는 스칼라 초보자입니다. 최근에 취미 앱을 작성하고 있었는데 많은 경우에 if-else 대신에 패턴 매칭을 사용하려고했습니다.
user.password == enteredPassword match {
case true => println("User is authenticated")
case false => println("Entered password is invalid")
}
대신에
if(user.password == enteredPassword)
println("User is authenticated")
else
println("Entered password is invalid")
이러한 접근 방식은 동일합니까? 어떤 이유로 그들 중 하나가 다른 것보다 더 선호됩니까?
class MatchVsIf {
def i(b: Boolean) = if (b) 5 else 4
def m(b: Boolean) = b match { case true => 5; case false => 4 }
}
더 길고 투박한 두 번째 버전을 사용하려는 이유를 잘 모르겠습니다.
scala> :javap -cp MatchVsIf
Compiled from "<console>"
public class MatchVsIf extends java.lang.Object implements scala.ScalaObject{
public int i(boolean);
Code:
0: iload_1
1: ifeq 8
4: iconst_5
5: goto 9
8: iconst_4
9: ireturn
public int m(boolean);
Code:
0: iload_1
1: istore_2
2: iload_2
3: iconst_1
4: if_icmpne 11
7: iconst_5
8: goto 17
11: iload_2
12: iconst_0
13: if_icmpne 18
16: iconst_4
17: ireturn
18: new #14; //class scala/MatchError
21: dup
22: iload_2
23: invokestatic #20; //Method scala/runtime/BoxesRunTime.boxToBoolean:(Z)Ljava/lang/Boolean;
26: invokespecial #24; //Method scala/MatchError."<init>":(Ljava/lang/Object;)V
29: athrow
그리고 그것은 일치에 대한 훨씬 더 많은 바이트 코드입니다. 그건 상당히 소형화 및 성능 하나 선호한다 위해 심지어 효율 (경기가 여기에 일어날 수 없다는 오류를 발생하지 않는 한 권투 없다)하지만, if/ else. 그러나 일치를 사용하여 코드의 명확성이 크게 향상되면 계속 진행하십시오 (성능이 중요하다는 것을 알고있는 드문 경우를 제외하고 차이점을 비교할 수 있음).
단일 부울에 대해 패턴 일치를 사용하지 마십시오. if-else를 사용하십시오.
덧붙여서 코드는 println.
println(
if(user.password == enteredPassword)
"User is authenticated"
else
"Entered password is invalid"
)
더 나은 방법은 "부울 블라인드"를 방지하기 때문에 비교 결과가 아니라 문자열에서 직접 패턴 일치를 수행하는 것입니다. http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/
한 가지 단점은 enterPassword 변수가 섀도 잉되지 않도록 보호하기 위해 역 따옴표를 사용해야한다는 것입니다.
기본적으로 부울은 유형 수준에서 정보를 전달하지 않기 때문에 가능한 한 많이 처리하지 않는 경향이 있습니다.
user.password match {
case `enteredPassword` => Right(user)
case _ => Left("passwords don't match")
}
두 명령문은 코드 의미론에서 동일합니다. 그러나 컴파일러가 한 경우 ( match) 에서 더 복잡한 (따라서 비효율적 인) 코드를 생성 할 수 있습니다 .
패턴 일치는 일반적으로 다형성 표현이나 unapply개체를 구성 요소로 분해 ( ing)하는 것과 같은 더 복잡한 구조를 분리하는 데 사용됩니다 . 간단한 if-else 문에 대한 대리자로 사용하라고 조언하지 않습니다. if-else 에는 아무런 문제가 없습니다 .
Scala에서 표현식으로 사용할 수 있습니다. 따라서 당신은 쓸 수 있습니다
val foo = if(bar.isEmpty) foobar else bar.foo
어리석은 예에 대해 사과드립니다.
성능에 민감하지 않은 대부분의 코드의 경우 if / else보다 패턴 일치를 사용하려는 많은 이유가 있습니다.
- 각 분기에 대해 공통 반환 값 및 유형을 적용합니다.
- 철저한 검사가있는 언어 (예 : Scala)에서는 모든 경우를 명시 적으로 고려하고 필요하지 않은 경우는 무시해야합니다.
- it prevents early returns, which become harder to reason if they cascade, grow in number, or the branches grow longer than the height of your screen (at which point they become invisible). Having an extra level of indentation will warn you you're inside a scope.
- it can help you identify logic to pull out. In this case the code could have been rewritten and made more DRY, debuggable, and testable like this:
val errorMessage = user.password == enteredPassword match {
case true => "User is authenticated"
case false => "Entered password is invalid"
}
println(errorMesssage)
Here's an equivalent if/else block implementation:
var errorMessage = ""
if(user.password == enteredPassword)
errorMessage = "User is authenticated"
else
errorMessage = "Entered password is invalid"
println(errorMessage)
Yes, you can argue that for something as simple as a boolean check you can use an if-expression. But that's not relevant here and doesn't scale well to conditions with more than 2 branches.
If your higher concern is maintainability or readability, pattern matching is awesome and you should use it for even minor things!
I'v came across same question, and had written tests:
def factorial(x: Int): Int = {
def loop(acc: Int, c: Int): Int = {
c match {
case 0 => acc
case _ => loop(acc * c, c - 1)
}
}
loop(1, x)
}
def factorialIf(x: Int): Int = {
def loop(acc: Int, c: Int): Int =
if (c == 0) acc else loop(acc * c, c - 1)
loop(1, x)
}
def measure(e: (Int) => Int, arg:Int, numIters: Int): Long = {
def loop(max: Int): Unit = {
if (max == 0)
return
else {
val x = e(arg)
loop(max-1)
}
}
val startMatch = System.currentTimeMillis()
loop(numIters)
System.currentTimeMillis() - startMatch
}
val timeIf = measure(factorialIf, 1000,1000000)
val timeMatch = measure(factorial, 1000,1000000)
timeIf : Long = 22 timeMatch : Long = 1092
I am here to offer a different opinion: For the specific example you offer, the second one (if...else...) style is actually better because it is much easier to read.
In fact, if you put your first example into IntelliJ, it will suggest you to change to the second (if...else...) style. Here is the IntelliJ style suggestion:
Trivial match can be simplified less... (⌘F1)
Suggests to replace trivial pattern match on a boolean expression with a conditional statement.
Before:
bool match {
case true => ???
case false => ???
}
After:
if (bool) {
???
} else {
???
}
In my environment (scala 2.12 and java 8) I get different results. Match performs consistently better in the code above:
timeIf: Long = 249 timeMatch: Long = 68
참고URL : https://stackoverflow.com/questions/9266822/pattern-matching-vs-if-else
'developer tip' 카테고리의 다른 글
| 이전 인증을 사용하여 MySQL 4.1+에 연결할 수 없습니다. (0) | 2020.11.07 |
|---|---|
| 사전에 색인을 생성하는 방법은 무엇입니까? (0) | 2020.11.07 |
| 덤프 파일을 사용하여 메모리 누수를 진단하려면 어떻게합니까? (0) | 2020.11.07 |
| 하위 요소의 불투명도 재설정-Maple Browser (삼성 TV 앱) (0) | 2020.11.07 |
| Python 16 진수 (0) | 2020.11.07 |