Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用其中一个来处理Scala代码中的故障_Scala_Functional Programming_Either - Fatal编程技术网

使用其中一个来处理Scala代码中的故障

使用其中一个来处理Scala代码中的故障,scala,functional-programming,either,Scala,Functional Programming,Either,Optionmonad是处理Scala中的有事或无事的一种很好的表达方式。但是如果一个人需要在“什么都没有”的情况下记录一条消息呢?根据Scala API文档 这两种类型中的任何一种都经常用作 scala.Option的替代选项(左) 表示失败(按惯例)和 右类似于某些 然而,我并没有幸运地找到最佳实践,而是使用了一个或多个涉及处理失败的实例。最后,我为自己的项目编写了以下代码: def logs: Array[String] = { def props: Option[

Option
monad是处理Scala中的有事或无事的一种很好的表达方式。但是如果一个人需要在“什么都没有”的情况下记录一条消息呢?根据Scala API文档

这两种类型中的任何一种都经常用作 scala.Option的替代选项(左) 表示失败(按惯例)和 右类似于某些

然而,我并没有幸运地找到最佳实践,而是使用了一个或多个涉及处理失败的实例。最后,我为自己的项目编写了以下代码:

    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)
    }
def日志:数组[字符串]={
def props:Option[Map[String,Any]]=configAdmin.Map{ca=>
val config=ca.getConfiguration(PID,null)
config.properties getOrElse immutable.Map.empty
}
def checkType(任意:任意):选项[Array[String]]=任意匹配{
案例a:数组[String]=>Some(a)
案例=>无
}
def查找:要么[(符号,字符串),要么数组[字符串]]=
对于{val属性“'logs'未在配置中定义”)。对吗
val数组日志(LogService.WARNING,msg)
案例('debug,msg)=>log(LogService.debug,msg)
案例=>
};新数组[String](0)},成功=>success)
}
(请注意,这是一个真实项目的片段,因此它不会自行编译)


我很高兴知道您是如何在代码中使用
和/或更好地重构上述代码的。

或用于返回两个可能有意义的结果中的一个,而不是用于返回单个有意义的结果或不返回任何结果的选项

下面给出了一个易于理解的示例(不久前在Scala邮件列表中传阅):

正如函数名所示,如果“block”的执行成功,它将返回“Right()”。否则,如果抛出一个Throwable,它将返回“Left()”。使用模式匹配来处理结果:

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

希望能有所帮助。

您发布的代码片段似乎很做作。您可以在以下情况下使用:

  • 仅仅知道数据不可用是不够的
  • 您需要返回两种不同类型中的一种
  • 事实上,将异常转换为左异常是一个常见的用例。与try/catch相比,它的优点是将代码保持在一起,如果异常是预期的结果,这是有意义的。最常见的处理方法是模式匹配:

    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
    

    所以,基本用法都是这样的。这不是一个特别有用的类,但如果是的话,你以前会看到它的。另一方面,它也不是无用的。

    Scalaz库有一些类似的东西,命名为Validation。它比“获取有效结果或失败”更为惯用

    验证还允许累积错误

    Edit:“like”或者是完全错误的,因为Validation是一个应用函子,scalaz或者是一个名为\/(发音为“disjonction”或者“other”)的单子。 验证可以累积错误的事实就是因为这种性质。另一方面,/具有“提前停止”的性质,在它遇到的第一个-\/(读“左”或“错误”)处停止。这里有一个完美的解释:

    见:

    根据评论的要求,复制/粘贴上述链接(删除部分行):

    //提取成功或失败值
    val s:验证[String,Int]=1.success
    val f:验证[String,Int]=“error”。失败
    //建议使用折叠而不是模式匹配:
    val结果:String=s.fold(e=>“获得错误:”+e,s=>“获得成功:”+s.toString)
    比赛{
    案例成功(a)=>“成功”
    案例失败(e)=>“失败”
    }
    //验证是一个单子,可以用于理解。
    val k1=用于{
    
    iCats有一个很好的方法,可以从异常抛出代码创建一个或:

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

    中,我在奥德斯基的书中也找不到关于它的任何提及。是的,我有“Scala编程”我所知道的最好的类比是Liftweb中的Box,它也用于承载故障——它类似于Option,但具有额外的功能。有没有比
    Option[任择[Foo,Bar]更好的替代方案
    ?奇怪…为什么不直接抛出异常?到处都是异常处理代码是很难看的,也很难管理。使用throwableToLeft将异常处理转化为模式匹配,更易于阅读和维护。例如,您可能有多个参与者同时执行不同的计算,其中一些实际上是eturn一个结果,有些则抛出一个异常。如果您只是抛出异常,其中一些参与者可能还没有开始工作,您将丢失任何尚未完成的参与者的结果,等等。使用这种方法,所有参与者都将返回一个值(一些
    ,一些
    )而且它最终更容易处理。@skaffman同样,你不能“发送异常”在斯卡拉2.10中有<代码> Scala。UTI.Test< /Cord>类,它本质上是一个特殊的代码< <代码> >异常处理,所以如果你做了上面的例子,那么就要考虑一下。似乎返回了相同的问题书,对吗?是的,它会。我知道它有一个平面图技巧,但我在编写示例时找不到它。这将是一件好事
    
    // 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"))
    
    val either: Either[NumberFormatException, Int] =
      Either.catchOnly[NumberFormatException]("abc".toInt)
    // either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")