Scala while(true) 类型不匹配?Scala 中的无限循环?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10802917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala while(true) type mismatch? Infinite loop in scala?
提问by TN.
Why following code
为什么下面的代码
def doSomething() = "Something"
var availableRetries: Int = 10
def process(): String = {
while (true) {
availableRetries -= 1
try {
return doSomething()
} catch {
case e: Exception => {
if (availableRetries < 0) {
throw e
}
}
}
}
}
produces following compiler error
产生以下编译器错误
error: type mismatch;
found : Unit
required: String
while (true) {
^
?
?
This works ok in C#. The while loops forever, so it cannot terminate, therefore it cannot result something else than string. Or how to make infinite loop in Scala?
这在 C# 中工作正常。while 永远循环,所以它不能终止,因此它不能产生除字符串之外的其他东西。或者如何在 Scala 中进行无限循环?
采纳答案by TN.
Based on senia, elbowichand dave's solutions I used following:
基于senia、echelich和dave的解决方案,我使用了以下方法:
@annotation.tailrec
def retry[T](availableRetries: Int)(action: => T): T = {
try {
return action
} catch {
case e: Exception if (availableRetries > 0) => { }
}
retry(availableRetries - 1)(action)
}
Which can be then used as elbowich and dave's solutions:
然后可以用作肘部和戴夫的解决方案:
retry(3) {
// some code
}
回答by James Iry
Unlike C# (and Java and C and C++) which are statement based languages, Scala is an expression based language. That's mostly a big plus in terms of composibility and readability but in this case the difference has bitten you.
与基于语句的语言 C#(以及 Java 和 C 和 C++)不同,Scala 是一种基于表达式的语言。在可组合性和可读性方面,这主要是一个很大的优势,但在这种情况下,差异已经让你大吃一惊。
A Scala method implicitly returns the value of the last expression in the method
Scala 方法隐式返回方法中最后一个表达式的值
scala> def id(x : String) = x
id: (x: String)String
scala> id("hello")
res0: String = hello
In Scala pretty much everything is an expression. Things that look like statements are still expressions that return a value of a type called Unit. The value can be written as ().
在 Scala 中,几乎一切都是表达式。看起来像语句的东西仍然是返回称为 Unit 类型的值的表达式。该值可以写为 ()。
scala> def foo() = while(false){}
foo: ()Unit
scala> if (foo() == ()) "yes!" else "no"
res2: java.lang.String = yes!
No compiler for a Turing-equivalent language can detect all non-terminating loops (c.f. Turing halting problem) so most compilers do very little work to detect any. In this case the type of "while(someCondition){...}" is Unit no matter what someCondition is, even if it's the constant true.
没有图灵等效语言的编译器可以检测所有非终止循环(参见图灵停止问题),因此大多数编译器几乎不做任何工作来检测任何循环。在这种情况下,无论 someCondition 是什么,“while(someCondition){...}”的类型都是 Unit,即使它是常量 true。
scala> def forever() = while(true){}
forever: ()Unit
Scala determines that the declared return type (String) isn't compatible with the actual return type (Unit), which is the type of the last expression (while...)
Scala 确定声明的返回类型 (String) 与实际返回类型 (Unit) 不兼容,后者是最后一个表达式的类型 (while...)
scala> def wtf() : String = while(true){}
<console>:5: error: type mismatch;
found : Unit
required: String
def wtf() : String = while(true){}
Answer: add an exception at the end
答:在最后添加一个例外
scala> def wtfOk() : String = {
| while(true){}
| error("seriously, wtf? how did I get here?")
| }
wtfOk: ()String
回答by senia
Functional way to define an infinite loop is recursion:
定义无限循环的函数方式是递归:
@annotation.tailrec def process(availableRetries: Int): String = {
try {
return doSomething()
} catch {
case e: Exception => {
if (availableRetries < 0) {
throw e
}
}
}
return process(availableRetries - 1)
}
elbowich's retryfunction without inner loopfunction:
elbowich的retry功能无内loop功能:
import scala.annotation.tailrec
import scala.util.control.Exception._
@tailrec def retry[A](times: Int)(body: => A): Either[Throwable, A] = {
allCatch.either(body) match {
case Left(_) if times > 1 => retry(times - 1)(body)
case x => x
}
}
回答by Rex Kerr
The compiler isn't smart enough to know that you can't exit the while loop, unfortunately. It's easy to trick, though, even if you can't sensibly generate a member of the return type--just throw an exception.
不幸的是,编译器不够聪明,无法知道您无法退出 while 循环。但是,即使您不能明智地生成返回类型的成员,也很容易被欺骗——只需抛出异常即可。
def process(): String = {
while (true) {
...
}
throw new Exception("How did I end up here?")
}
Now the compiler will realize that even if it escapes the while loop, it can't return a value there, so it doesn't worry that the while loop has return type Unit(i.e. does not return a value).
现在编译器会意识到,即使它逃脱了while循环,它也无法在那里返回值,因此不必担心while循环有返回类型Unit(即不返回值)。
回答by elbowich
import scala.annotation.tailrec
import scala.util.control.Exception._
def retry[A](times: Int)(body: => A) = {
@tailrec def loop(i: Int): Either[Throwable, A] =
allCatch.either(body) match {
case Left(_) if i > 1 => loop(i - 1)
case x => x
}
loop(times)
}
retry(10) {
shamelessExceptionThrower()
}
回答by Dylan
edit:I just noticed the actual return statement. The return statement inside the while loop will be ignored. For example, in the REPL:
编辑:我刚刚注意到实际的 return 语句。while 循环中的 return 语句将被忽略。例如,在 REPL 中:
scala> def go = while(true){return "hi"}
<console>:7: error: method go has return statement; needs result type
def go = while(true){return "hi"}
^
You told the compiler that the process()method returns a String, but your method body is just a whileloop, which doesn't return anything (it's a Unit, or a Java void). Either change the return type or add a String after the while loop.
您告诉编译器该process()方法返回 a String,但您的方法主体只是一个while循环,它不返回任何内容(它是 aUnit或 Java void)。要么更改返回类型,要么在 while 循环后添加一个字符串。
def process(): Unit = {
while(true){...}
}
or
或者
def process(): String = {
while(true){...}
"done"
}

