얼마 전 나는 자바 대신 스칼라를 사용하기 시작했다. 나를위한 언어들 사이의 "변환"과정의 일부는 Either
(확인 된) 대신 s 를 사용하는 방법을 배우고있었습니다 Exception
. 나는이 방법을 잠시 동안 코딩 해 왔지만 최근에 그것이 정말로 더 좋은 방법인지 궁금해하기 시작했습니다.
하나의 큰 장점은 Either
이상이 Exception
더 나은 성능이다; 는 Exception
스택 트레이스를 구축 할 필요가 던져되고있다. 내가 아는 한, 던지기 Exception
는 까다로운 부분이 아니라 스택 추적을 만드는 것입니다.
그러나, 하나는 항상 / 상속 구성 할 수 있습니다 Exception
와 함께 사용 scala.util.control.NoStackTrace
, 그리고 왼쪽 어디 더욱 그렇고, 나는 경우를 많이 볼 수 Either
사실에 Exception
(성능 향상을 삼가고).
또 다른 장점 Either
은 컴파일러 안전성입니다. Scala 컴파일러는 처리되지 않은 것에 대해 불평하지 않습니다 Exception
(Java 컴파일러와 달리). 그러나 내가 실수하지 않으면이 결정은이 주제에서 논의되는 것과 동일한 추론으로 추론됩니다.
구문 측면에서 보면 Exception
스타일이 더 명확 해 보입니다 . 다음 코드 블록을 검사하십시오 (둘 다 동일한 기능을 수행함).
Either
스타일:
def compute(): Either[String, Int] = {
val aEither: Either[String, String] = if (someCondition) Right("good") else Left("bad")
val bEithers: Iterable[Either[String, Int]] = someSeq.map {
item => if (someCondition(item)) Right(item.toInt) else Left("bad")
}
for {
a <- aEither.right
bs <- reduce(bEithers).right
ignore <- validate(bs).right
} yield compute(a, bs)
}
def reduce[A,B](eithers: Iterable[Either[A,B]]): Either[A, Iterable[B]] = ??? // utility code
def validate(bs: Iterable[Int]): Either[String, Unit] = if (bs.sum > 22) Left("bad") else Right()
def compute(a: String, bs: Iterable[Int]): Int = ???
Exception
스타일:
@throws(classOf[ComputationException])
def compute(): Int = {
val a = if (someCondition) "good" else throw new ComputationException("bad")
val bs = someSeq.map {
item => if (someCondition(item)) item.toInt else throw new ComputationException("bad")
}
if (bs.sum > 22) throw new ComputationException("bad")
compute(a, bs)
}
def compute(a: String, bs: Iterable[Int]): Int = ???
후자는 나에게 훨씬 깨끗해 보이며 실패를 처리하는 코드 (패턴 일치 on Either
또는 try-catch
)는 두 경우 모두 매우 분명합니다.
그래서 내 질문은-왜 Either
이상 사용 (확인) Exception
입니까?
최신 정보
답을 읽은 후, 나는 딜레마의 핵심을 제시하지 못했을 수도 있음을 깨달았습니다. 내 걱정은 하지 의 부족과 try-catch
; 하나는 중 "캐치"는 수 Exception
와 Try
, 또는를 사용 catch
에 예외를 포장 Left
.
Either
/의 주요 문제 Try
는 여러 지점에서 실패 할 수있는 코드를 작성할 때 발생합니다. 이러한 시나리오에서 오류가 발생하면 전체 코드에서 해당 오류를 전파해야하므로 앞에서 언급 한 예에 표시된 것처럼 코드가 더 번거로워집니다.
실제로는 스칼라에서 또 다른 "금기"를 Exception
사용하여 s 없이 코드를 깨는 또 다른 방법이 return
있습니다. 코드는 여전히 Either
접근 방식 보다 명확 하고 Exception
스타일 보다 약간 덜 깨끗하지만 잡히지 않을 염려가 없습니다 Exception
.
def compute(): Either[String, Int] = {
val a = if (someCondition) "good" else return Left("bad")
val bs: Iterable[Int] = someSeq.map {
item => if (someCondition(item)) item.toInt else return Left("bad")
}
if (bs.sum > 22) return Left("bad")
val c = computeC(bs).rightOrReturn(return _)
Right(computeAll(a, bs, c))
}
def computeC(bs: Iterable[Int]): Either[String, Int] = ???
def computeAll(a: String, bs: Iterable[Int], c: Int): Int = ???
implicit class ConvertEither[L, R](either: Either[L, R]) {
def rightOrReturn(f: (Left[L, R]) => R): R = either match {
case Right(r) => r
case Left(l) => f(Left(l))
}
}
기본적으로 return Left
replaces throw new Exception
및의 암시 적 방법 rightOrReturn
은 스택에 자동 예외 전파를 보완하는 것입니다.
Try
. Either
vs 에 관한 부분은 그 방법의 다른 경우가 "예외적이지 않은"경우에 s가 사용되어야한다고 Exception
명시하고 Either
있다. 첫째, 이것은 매우 모호한 정의 imho입니다. 둘째, 구문 위약금의 가치가 있습니까? 내 말은, Either
구문 오버 헤드가 아니라면 s를 사용하는 것이 실제로 마음에 들지 않을 것 입니다.
Either
나에게 모나드처럼 보인다. 모나드가 제공하는 기능적 구성 혜택이 필요할 때 사용하십시오. 또는 아닐 수도 있습니다.
Either
그 자체로는 모나드가 아닙니다. 왼쪽 또는 오른쪽으로 의 투영 은 모나드이지만 Either
그 자체로는 그렇지 않습니다. 그래도 왼쪽이나 오른쪽에 "바이어 싱"하여 모나드로 만들 수 있습니다 . 그러나의 양쪽에 특정 의미를 부여합니다 Either
. 스칼라 Either
는 원래 편견이 없었지만 최근에 편향되어 있었기 때문에 오늘날에는 실제로 모나드이지만 "모나드 니스"는 고유 속성이 Either
아니라 편향의 결과입니다.