1

玩一些 Scala,似乎你不能从一个函数中提前返回。

我发现带有早期返回的扁平未缩进代码很容易遵循。我最初的尝试创建了一个大的嵌套结构。叫我挑剔,但我不喜欢看到以下内容:

    }
  }
}

在 Scala 中编写以下方法的最佳方法是什么?

是否有可能以减少嵌套的方式进行编程,或者我会一直与 Scala 的功能设计理念作斗争?

@Nullable
public static <T extends PsiElement> T getParentOfType(@Nullable PsiElement element,
                                                       @NotNull Class<T> aClass,
                                                       boolean strict,
                                                       @NotNull Class<? extends PsiElement>... stopAt) {
  if (element == null) return null;
  if (strict) {
    element = element.getParent();
  }

  while (element != null && !aClass.isInstance(element)) {
    if (instanceOf(element, stopAt)) return null;
    if (element instanceof PsiFile) return null;
    element = element.getParent();
  }

  //noinspection unchecked
  return (T)element;
}

我的尝试:

def getParentOfType[T](element: PsiElement, aClass: Class, strict: Boolean): T[_ <: PsiElement] = {
  element match {
    case null => null
    case _ => {
      var el = if (strict) {
        element.getParent
      } else element
      while(el != null) {
        if (aClass isInstance el) {
          return el
        }
        if (el.isInstanceOf[PsiFile]) return null;
        el = el.getParent()
      }
    }
  }
}

此外,在 Scala 世界中,什么是合适的论坛来询问“在 Scala 中编写 Java 方法 X 的最佳方法是什么?”。我发现自己经常问这个问题。

4

3 回答 3

5
def getParentOfType[T](element: PsiElement, aClass: Class, strict: Boolean):
    T[_ <: PsiElement] = element match {
  case null => null
  case el if strict => getParentOfType(el.getParent, aClass, false)
  case el if aClass isInstance el => el
  case el if el.isInstanceOf[PsiFile] => null
  case el => getParentOfType(el.getParent, aClass, false)
}

(或类似的)

于 2013-06-25T15:13:40.230 回答
1

很难将 scala 与null. 而且您无法使用while.

你有@Nullableand @NotNull- 在 scala 它是Option[T]and T。您可以while用递归方法替换。

例如,这是我尝试将您的方法转换为 scala(未测试):

getParentOfType[T <: PsiElement](element: Option[PsiElement],
                                 aClass: Class[T],
                                 strict: Boolean,
                                 stopAt: Class[_ <: PsiElement]*): Option[T] = element flatMap { el =>
  @tailrec def loop(element: PsiElement): Option[PsiElement] {
    if (element == null || aClass.isInstance(element))
      Option(element)
    else if (instanceOf(element, stopAt) || element.isInstanceOf[PsiFile])
      None
    else
      loop(element.getParent())
  }

  loop(if (strict) el.getParent() else el).map{_.asInstanceOf[T]}
}
于 2013-06-25T15:12:50.330 回答
1

这是对这个问题的不同看法;可能不是我在这种特殊情况下使用的,但值得了解。

def getParentOfType[A >: Null <: PsiElement](
  element: PsiElement, aClass: Class[A],
  strict: Boolean, stopAt: Class[_ <: PsiElement]*
): A =
  Iterator.iterate(element)(_.getParent).
  takeWhile(_ != null).
  drop(if (strict) 1 else 0).
  takeWhile(e => !instanceOf(e, stopAt) && !e.isInstanceOf[PsiFile]).
  collectFirst{ case x if aClass isInstance x => x.asInstanceOf[A] }.
  orNull

在这里,您首先定义元素的父级流,如果它为空则终止。如果您的严格标志为真,则放弃第一个;如果您在stopAtPsiFile. 在这些约束中,您获得(并强制转换)第一个匹配的内容,然后如果您没有得到任何内容,则返回该内容或 null。

通过一些练习,实际上遵循这种逻辑比循环更容易,因为循环中的终止条件比这里更隐含。在这里,您只需明确说明当您停止搜索时 ( takeWhile) 以及您所追求的 ( collectFirst)。

注意:我假设instanceOf定义为

def instanceOf(a: AnyRef, cs: Seq[Class[_]]) = cs.exists(_ isInstance a)
于 2013-06-25T16:10:53.150 回答