Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.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打破集合的惯用方式是什么;s`find`方法在出现错误时失败?_Scala_Collections - Fatal编程技术网

Scala打破集合的惯用方式是什么;s`find`方法在出现错误时失败?

Scala打破集合的惯用方式是什么;s`find`方法在出现错误时失败?,scala,collections,Scala,Collections,打破find循环并将其映射到失败的惯用方法是什么 我希望避免使用异常(抛出异常并将其包装到Try()中) 我想避免使用return 这应该或多或少有性能(因此我相信递归不会工作,也不会折叠,因为它会将集合扫描到底) 也许吧 def findUseById(userId: Long, usersJson: Seq[JsObject]): Try[Option[JsObject]] = { usersJson.find { userJson => (userJson \ "id"

打破find循环并将其映射到失败的惯用方法是什么

  • 我希望避免使用异常(抛出异常并将其包装到Try()中)
  • 我想避免使用
    return
  • 这应该或多或少有性能(因此我相信递归不会工作,也不会折叠,因为它会将集合扫描到底)
  • 也许吧

    def findUseById(userId: Long, usersJson: Seq[JsObject]): Try[Option[JsObject]] = {
      usersJson.find { userJson =>
        (userJson \ "id").validate[Long] {
          case Right(uid) => uid == userId
          case Left(error) =>
          // How to break find loop and  "map" it to failure 
          // (like Failure(new SomeException())) ?
        }
      }
    }
    

    尽管这违反了您的第一个要求。

    这里有一个简单、高效且功能强大的问题解决方案。
    它利用了迭代器的惰性和
    collectFirst
    提前返回的优势

    但是,我不确定选项的尝试是否是最好的类型。
    例如,您可以只删除结尾处的匹配项,并返回一个Try选项,或者只对找不到的值使用自定义异常

    import scala.util.{Failure, Success, Try}
    
    def validateAndFind[A, B](data: Seq[A], target: B)
                             (validationFun: A => Either[Throwable, (A, B)]): Try[Option[A]] =
      data
        .iterator
        .map(validationFun)
        .collectFirst {
          case Right((elem, value)) if (value == target) => Right(elem)
          case Left(ex)                                  => Left(ex)
        } match {
          case None              => Success(None)
          case Some(Right(elem)) => Success(Some(elem))
          case Some(Left(ex))    => Failure(ex)
        }
    
    无论如何,这两种代码都是等效的,并按预期工作:

    sealed trait ValidationError extends Product with Serializable
    final case object ElementNotFound extends ValidationError
    final case class ValidationFailure(cause: Throwable) extends ValidationError
    
    def validateAndFind[A, B](data: Seq[A], target: B)
                             (validationFun: A => Either[Throwable, (A, B)]): Either[ValidationError, A] =
      data
        .iterator
        .map(validationFun)
        .collectFirst {
          case Right((elem, value)) if (value == target) => Right(elem)
          case Left(ex)                                  => Left(ValidationFailure(cause = ex))
        }.getOrElse(Left(ElementNotFound))
    
    最终案例类用户(名称:String,年龄:Int)
    验证查找(
    数据=列表(
    用户(name=“Balmung”,年龄=22岁),
    用户(name=“Luis”,年龄=22岁),
    用户(name=“Miguel”,年龄=22岁)
    ),
    target=“路易斯”
    ){user=>
    println(s“验证用户:${user}”)
    如果(user.age<18)离开(新的IllegalArgumentException(“未成年用户”))
    else权限(用户->用户名)
    }
    //验证用户:用户(Balmung,22岁)
    //验证用户:用户(Luis,22)
    //res:not[ValidationError,User]=右(User(“Luis”,22))
    
    如您所见,它没有验证第三个元素,因为它不是必需的。
    让我们看看另外两个要求

    final case class User(name: String, age: Int)
    
    validateAndFind(
      data = List(
        User(name = "Balmung", age = 22),
        User(name = "Luis", age = 22),
        User(name = "Miguel", age = 22)
      ),
      target = "Luis"
    ) { user =>
      println(s"Validating user: ${user}")
      if (user.age < 18) Left(new IllegalArgumentException("User underage"))
      else Right(user -> user.name)
    }
    
    // Validating user: User(Balmung,22)
    // Validating user: User(Luis,22)
    // res: Either[ValidationError, User] = Right(User("Luis", 22))
    
    validateAndFind(
    数据=列表(
    用户(name=“Balmung”,年龄=16岁),
    用户(name=“Luis”,年龄=22岁),
    用户(name=“Miguel”,年龄=22岁)
    ),
    target=“路易斯”
    ){user=>
    println(s“验证用户:${user}”)
    如果(user.age<18)离开(新的IllegalArgumentException(“未成年用户”))
    else权限(用户->用户名)
    }
    //验证用户:用户(Balmung,16岁)
    //res:not[ValidationError,User]=左(ValidationFailure(java.lang.IllegalArgumentException:未成年用户))
    

    validateAndFind(
    数据=列表(
    用户(name=“Balmung”,年龄=22岁),
    用户(name=“Luis”,年龄=22岁),
    用户(name=“Miguel”,年龄=22岁)
    ),
    target=“马里奥”
    ){user=>
    println(s“验证用户:${user}”)
    如果(user.age<18)离开(新的IllegalArgumentException(“未成年用户”))
    else权限(用户->用户名)
    }
    //验证用户:用户(Balmung,22岁)
    //验证用户:用户(Luis,22)
    //验证用户:用户(Miguel,22岁)
    //res:not[ValidationError,User]=左(ElementNotFound)
    
    您可以使用
    return
    @jrook
    return
    提前返回在函数式编程中有点不惯用至少在Scala 2.13集合中,
    find
    方法使用
    return
    (除了java风格
    while
    循环之外)。我想不出比立即从函数返回并继续执行程序其余部分更有效的方法了。@jrook Scala的集合实现本身不是惯用的,因为这些函数概念最终应该以某种方式映射到JVM。。它们为我们提供了编写惯用代码的api。如果您在列表的第三个位置找到了值,但第五个项目没有验证,那么预期的行为是什么?它应该返回成功还是验证错误?我认为
    .map(\u==userId)
    应该是
    .map(\ucode.get==userId)
    @jrook您可能是对的。由于我不确定使用的是什么库,所以我假设
    validateOpt
    返回一个类似于播放json的
    选项
    
    final case class User(name: String, age: Int)
    
    validateAndFind(
      data = List(
        User(name = "Balmung", age = 22),
        User(name = "Luis", age = 22),
        User(name = "Miguel", age = 22)
      ),
      target = "Luis"
    ) { user =>
      println(s"Validating user: ${user}")
      if (user.age < 18) Left(new IllegalArgumentException("User underage"))
      else Right(user -> user.name)
    }
    
    // Validating user: User(Balmung,22)
    // Validating user: User(Luis,22)
    // res: Either[ValidationError, User] = Right(User("Luis", 22))
    
    validateAndFind(
      data = List(
        User(name = "Balmung", age = 16),
        User(name = "Luis", age = 22),
        User(name = "Miguel", age = 22)
      ),
      target = "Luis"
    ) { user =>
      println(s"Validating user: ${user}")
      if (user.age < 18) Left(new IllegalArgumentException("User underage"))
      else Right(user -> user.name)
    }
    
    // Validating user: User(Balmung,16)
    // res: Either[ValidationError, User] = Left(ValidationFailure(java.lang.IllegalArgumentException: User underage))
    
    validateAndFind(
      data = List(
        User(name = "Balmung", age = 22),
        User(name = "Luis", age = 22),
        User(name = "Miguel", age = 22)
      ),
      target = "Mario"
    ) { user =>
      println(s"Validating user: ${user}")
      if (user.age < 18) Left(new IllegalArgumentException("User underage"))
      else Right(user -> user.name)
    }
    
    // Validating user: User(Balmung,22)
    // Validating user: User(Luis,22)
    // Validating user: User(Miguel,22)
    // res: Either[ValidationError, User] = Left(ElementNotFound)