如何从scala中的for循环返回生成的值?

如何从scala中的for循环返回生成的值?,scala,Scala,在我的项目中,我们正在从Java迁移到Scala。我必须使用Java中的一个函数,该函数使用continue in for循环,并根据for循环中的if条件返回一个值,如下所示 private TSourceToken getBeforeToken(TSourceToken token) { TSourceTokenList tokens = token.container; int index = token.posinlist; for ( int i = index

在我的项目中,我们正在从Java迁移到Scala。我必须使用Java中的一个函数,该函数使用continue in for循环,并根据for循环中的if条件返回一个值,如下所示

private TSourceToken getBeforeToken(TSourceToken token) {
  TSourceTokenList tokens = token.container;
  int index = token.posinlist;     
  for ( int i = index - 1; i >= 0; i-- ) {
    TSourceToken currentToken = tokens.get( i );
    if ( currentToken.toString( ).trim( ).length( ) == 0 ) {
      continue;
    }
    else {
      return currentToken;
    }
  }
  return token;
}
def getBeforeToken(token: TSourceToken): TSourceToken = {
  val tokens = token.container
  val index = token.posinlist

  for { i <- index -1 to 0 by -1
        currentToken = tokens.get(i)
        if(currentToken.toString.trim.length != 0)
        } yield currentToken

}
为了将其转换为Scala,我使用了Yield选项以过滤掉满足if表达式else条件的值,如下所示

private TSourceToken getBeforeToken(TSourceToken token) {
  TSourceTokenList tokens = token.container;
  int index = token.posinlist;     
  for ( int i = index - 1; i >= 0; i-- ) {
    TSourceToken currentToken = tokens.get( i );
    if ( currentToken.toString( ).trim( ).length( ) == 0 ) {
      continue;
    }
    else {
      return currentToken;
    }
  }
  return token;
}
def getBeforeToken(token: TSourceToken): TSourceToken = {
  val tokens = token.container
  val index = token.posinlist

  for { i <- index -1 to 0 by -1
        currentToken = tokens.get(i)
        if(currentToken.toString.trim.length != 0)
        } yield currentToken

}
我知道从for循环及其内部条件收集所有值会产生一个集合:IndexedSeq&因此会产生错误消息。我想不出一个逻辑形式,因为它是在Java代码中编写的。 有人能告诉我如何在Scala中构建代码而不使用yield,并在满足else条件后中断for循环吗?

Scala中没有java中那样的for循环。因为产量和循环不同。它只是flatMap、map和withFilter函数组合的语法糖。在scala中,最好不要使用return关键字。基于具有返回值和返回词的表达式的语言可能会破坏逻辑,而其他开发人员不能期望这样

在您的情况下,最好使用find按谓词查找某些集合中的特定元素:

def getBeforeToken(token: TSourceToken): TSourceToken = {
  val tokens = token.container
  val index = token.posinlist

  (index - 1 to 0 by -1)
    .find(i => tokens.get(i).toString.trim.length != 0)
    .fold(token)(i => tokens.get(i))
}

您可以阅读很多有关Scala产量的信息。以下是一些不错的文章:

通过Scala文档。 通过Scala文档。 阿尔文·亚历山大 作者@Dario。 但我认为在Scala中这样做是错误的。Scala是一种函数式编程语言,您可以使用它的能力

假设TSourceToken是具有两个成员的case类:

case class TSourceToken(container: Seq[String], posinlist: Int)
您要从最后一个posinlist标记中选择不是空的最后一个标记。有很多方法可以实现这一点。我想到的一个方法是:

val tokens = TSourceToken(Seq("", "   ", "  \n   ", "real token", "\t\t", "   ", "  \n\n  ", "token to ignore"), 5)
val token = tokens.container.take(tokens.posinlist).filter(_.trim.nonEmpty).last

正如您所期望的,令牌将具有真实令牌。代码运行可以在找到。

a for comprehension不是解决此问题的正确工具:它用于映射,而不是查找

对于只将java代码重新写入scala的直接重写,请使用while循环:

def getBeforeToken(token: TSourceToken): TSourceToken = {
  val tokens = token.container
  var i = index - 1
  while (i >= 0) {
    val currentToken = tokens.get(i)
    if (currentToken.toString.trim.length != 0) return currentToken
    i -= 1
  }
  token
}
但是,如果token.container是某个集合,您可能会编写它而不进行显式迭代:

def getBeforeToken(token: TSoruceToken): TSourceToken =
  token.container.reverseIterator.collectFirst {
    case t if t.toString.trim.length != 0 => t
  }.getOrElse(token)

在迁移过程中,最好还是坚持第一个,在尝试提高scala代码质量之前,尽快完成几乎机械化的翻译。

因此,在这种情况下,我们会发现只要打破第一个值的循环,条件就满足了吗?我的理解正确吗?@Metadata是的,它会找到第一个满意的令牌,或者使用传递给GetOrelse的默认值。我觉得这可能更容易反转,比如token.container.view.takeindex.reverse.find_u.toString.trim.nonEmpty.getOrElsetokenoh ok。。现在明白了。它是一个java迭代器。为什么不将它转换为Scala类型呢?