복붙노트

[SCALA] 하나를 사용하여 스칼라 코드에서 오류를 처리하는

SCALA

하나를 사용하여 스칼라 코드에서 오류를 처리하는

옵션 모나드는 스칼라에서 뭔가 아니면도 일을 처리 할 수있는 좋은 표현 방법입니다. 그러나 하나는 "아무것도"발생시 메시지를 기록 무엇을해야하는지? 스칼라 API 문서에 따르면,

그러나, 나는 중 하나 또는 어느 처리 실패에 대한 관련된 좋은 실제 사례를 사용하여 모범 사례를 찾을 수 운이 없었다. 마지막으로 나는 내 자신의 프로젝트에 대한 다음 코드로 왔어요 :

    def logs: Array[String] = {
        def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
            val config = ca.getConfiguration(PID, null)
            config.properties getOrElse immutable.Map.empty
        }
        def checkType(any: Any): Option[Array[String]] = any match {
            case a: Array[String] => Some(a)
            case _ => None
        }
        def lookup: Either[(Symbol, String), Array[String]] =
            for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
                 val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
                 val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
            yield array

        lookup.fold(failure => { failure match {
            case ('warning, msg) => log(LogService.WARNING, msg)
            case ('debug, msg) =>   log(LogService.DEBUG, msg)
            case _ =>
        }; new Array[String](0) }, success => success)
    }

(이 실제 프로젝트에서 코드 조각입니다주의, 그래서 그 자체로 컴파일되지 않습니다하시기 바랍니다)

난 당신이 사용하는 어느 코드 및 / 또는 위의 코드를 리팩토링에 대한 더 나은 아이디어를하는 방법을 알고 감사하게 될 거라고.

해결법

  1. ==============================

    1.하나 하나의 의미있는 결과 또는 아무것도를 반환하는 데 사용되는 옵션과는 달리, 가능한 두 개의 의미있는 결과 중 하나를 반환하는 데 사용됩니다.

    하나 하나의 의미있는 결과 또는 아무것도를 반환하는 데 사용되는 옵션과는 달리, 가능한 두 개의 의미있는 결과 중 하나를 반환하는 데 사용됩니다.

    예를 들어 이해하기 쉬운은 (스칼라 메일 링리스트 잠시 뒤에 순환) 아래에 주어진다 :

    def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] =
      try {
        Right(block)
      } catch {
        case ex => Left(ex)
      }
    

    함수 이름에서 알 수 있듯이 "블록"의 실행이 성공하면, 그것은 "오른쪽 (<결과>)"를 반환합니다. Throwable에이 발생합니다 그렇지 않으면, 그것은 "(<던질 수>) 왼쪽"을 반환합니다. 결과를 처리하는 패턴 매칭을 사용하여

    var s = "hello"
    throwableToLeft { s.toUpperCase } match {
      case Right(s) => println(s)
      case Left(e) => e.printStackTrace
    }
    // prints "HELLO"
    
    s = null
    throwableToLeft { s.toUpperCase } match {
      case Right(s) => println(s)
      case Left(e) => e.printStackTrace
    }
    // prints NullPointerException stack trace
    

    희망이 도움이.

  2. ==============================

    2.Scalaz 라이브러리는 모두 하나 검증이라는 것이있다. 그것은보다 어느 사용으로 "유효한 결과 또는 오류 중 하나를 얻을"더 관용적이다.

    Scalaz 라이브러리는 모두 하나 검증이라는 것이있다. 그것은보다 어느 사용으로 "유효한 결과 또는 오류 중 하나를 얻을"더 관용적이다.

    또한 유효성 검사 오류를 축적 할 수 있습니다.

    편집 : 검증이 실용적 펑터이며, \ / (발음 "disjonction"또는 "하나")라는 이름의 scalaz 하나, 모나드 때문에 "모두"하나는, complettly false입니다. 유효성 검사 오류를 accumalate 수 있다는 사실 때문에 그 성격이다. 반면에, / 처음에 정지하는 "초 정지"자연이 - \ /이 발견 ( "오류"가 "왼쪽"읽거나). 완벽한 설명은 여기에 있습니다 : http://typelevel.org/blog/2014/02/21/error-handling.html

    참조 : http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html

    (일부 라인 제거) 위의 링크의 코멘트, 복사 / 붙여 넣기의 요청에 따라 :

    // Extracting success or failure values
    val s: Validation[String, Int] = 1.success
    val f: Validation[String, Int] = "error".fail
    
    // It is recommended to use fold rather than pattern matching:
    val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString)
    
    s match {
      case Success(a) => "success"
      case Failure(e) => "fail"
    }
    
    // Validation is a Monad, and can be used in for comprehensions.
    val k1 = for {
      i <- s
      j <- s
    } yield i + j
    k1.toOption assert_≟ Some(2)
    
    // The first failing sub-computation fails the entire computation.
    val k2 = for {
      i <- f
      j <- f
    } yield i + j
    k2.fail.toOption assert_≟ Some("error")
    
    // Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup.
    // A number of computations are tried. If the all success, a function can combine them into a Success. If any
    // of them fails, the individual errors are accumulated.
    
    // Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor.
    val k4 = (fNel <**> fNel){ _ + _ }
    k4.fail.toOption assert_≟ some(nel1("error", "error"))
    
  3. ==============================

    3.당신이 게시 한 조각은 매우 인위적인 것 같다. 당신은 어디에 상황에서 하나를 사용하십시오

    당신이 게시 한 조각은 매우 인위적인 것 같다. 당신은 어디에 상황에서 하나를 사용하십시오

    왼쪽 버튼으로 예외를 설정하면 일반적인 사용 사례, 참이다. 이상 시도 / 캐치, 그것은 예외가 예상 된 결과 인 경우 의미가 함께 코드를 유지하는 장점을 가지고 있습니다. 어느 처리하는 가장 일반적인 방법은 패턴 매칭입니다 :

    result match {
      case Right(res) => ...
      case Left(res) => ...
    }
    

    이 콜렉션에 나타날 때 어느 처리의 또 다른 흥미로운 방법입니다. 모음을 통해지도를 수행 할 때, 예외를 던지고 가능한하지 않을 수 있습니다, 당신은 "불가능"이외의 정보를 반환 할 수 있습니다. 양자 택일을 사용하면 수행 할 수 있습니다 그 알고리즘 과부하를하지 않고 :

    val list = (
      library 
      \\ "books" 
      map (book => 
        if (book \ "author" isEmpty) 
          Left(book) 
        else 
          Right((book \ "author" toList) map (_ text))
      )
    )
    

    여기서 우리는 라이브러리에있는 모든 저자의 목록, 플러스 저자가없는 책의 목록을 얻을. 그래서 우리는 그것을 더 적절하게 처리 할 수 ​​있습니다 :

    val authorCount = (
      (Map[String,Int]() /: (list filter (_ isRight) map (_.right.get))) 
       ((map, author) => map + (author -> (map.getOrElse(author, 0) + 1)))
      toList
    )
    val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation
    

    따라서, 기본 중 하나를 사용 그렇게 간다. 그것은 특히 유용 클래스는 아니지만이 있다면 당신은 그것을 전에 본 것입니다. 다른 한편으로는 하나 쓸모가 아니다.

  4. ==============================

    4.고양이는 예외 던지는 코드에서 하나를 만들 수있는 좋은 방법이 있습니다 :

    고양이는 예외 던지는 코드에서 하나를 만들 수있는 좋은 방법이 있습니다 :

    val either: Either[NumberFormatException, Int] =
      Either.catchOnly[NumberFormatException]("abc".toInt)
    // either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")
    

    https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code에서

  5. from https://stackoverflow.com/questions/1193333/using-either-to-process-failures-in-scala-code by cc-by-sa and MIT license