gpt4 book ai didi

scala - scala : classOf[], exceptions and::operator for lists weird behavior

转载 作者:行者123 更新时间:2023-12-02 10:41:11 24 4
gpt4 key购买 nike

我在scala中遇到了一些非常奇怪的行为。
我编写了一个通用方法,该方法将容易出错的代码和“有效异常”列表作为参数,并且应该执行该代码,同时在抛出“有效异常”时重试该代码。

该方法很好用,我在几个地方使用它。
但是然后,其中一个方法调用在编译时失败。
原因是异常列表的初始化。

我已经在REPL中进行了尝试,以确保没有其他原因,您可以自己查看结果:

me@my-lap:~$ scala -cp /path/to/maven/repository/org/apache/httpcomponents/httpclient/4.1.1/httpclient-4.1.1.jar:/path/to/maven/repository/commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar:/path/to/maven/repository/me/my-utils/1.0-SNAPSHOT/my-utils-1.0-SNAPSHOT.jar:/path/to/maven/repository/org/apache/httpcomponents/httpcore/4.1/httpcore-4.1.jar
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import org.apache.http.conn.{HttpHostConnectException,ConnectTimeoutException}
import org.apache.http.conn.{HttpHostConnectException, ConnectTimeoutException}

scala> import me.util.exceptions.RetryException
import me.util.exceptions.RetryException

scala> val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
<console>:9: error: inferred type arguments [java.lang.Class[_ >: _1 with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] do not conform to method ::'s type parameter bounds [B >: java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException <: java.lang.Exception]]
val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
^

当初始化所有3种异常类型的列表时,代码将失败,并出现此奇怪的错误。
所以我试图用那些3的2个异常的每个子集进行初始化:
scala> val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: Nil
validEx: List[java.lang.Class[_ >: me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] = List(class org.apache.http.conn.ConnectTimeoutException, class me.util.exceptions.RetryException)

scala> val validEx = classOf[ConnectTimeoutException] :: classOf[HttpHostConnectException] :: Nil
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with org.apache.http.conn.ConnectTimeoutException <: java.io.IOException]] = List(class org.apache.http.conn.ConnectTimeoutException, class org.apache.http.conn.HttpHostConnectException)

scala> val validEx = classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException <: java.lang.Exception]] = List(class me.util.exceptions.RetryException, class org.apache.http.conn.HttpHostConnectException)

而且有效!我还尝试使用 List()而不是 ::运算符来创建所有3种异常类型的列表。它也起作用:
scala> val validEx = List(classOf[ConnectTimeoutException], classOf[RetryException], classOf[HttpHostConnectException])
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] = List(class org.apache.http.conn.ConnectTimeoutException, class me.util.exceptions.RetryException, class org.apache.http.conn.HttpHostConnectException)

顺便说一句, RetryException的实现是:
class RetryException extends Exception {}

那为什么会发生呢?是Scala的 ::运算符的错误吗?
以及为什么编译器无法推断出比以下更好的类型: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]](我的方法除类型为 validExceptions: List[Class[_ <: java.lang.Throwable]]的参数外,这是一种更为简洁的类型。除了编译器,我想找出类似的东西: List[Class[_ <: java.lang.Exception]]
(我正在使用Scala 2.9.2(Java7 oracle 1.7.0_17)在ubuntu 12.04 64bit上运行

最佳答案

这看起来只是一个推断问题。

尝试将Nil替换为List.empty[Exception]:

val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: List.empty[Class[_ <: Exception]]

这应该解决它。

现在,让我们看看原始代码中发生了什么:
val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil

这是从右到左评估的,因为 ::是右关联的。

因此,首先,编译器评估 classOf[HttpHostConnectException] :: Nil。推断的类型为 List[Class[HttpHostConnectException]]
我们将此表达式的结果称为 tmp1: List[Class[HttpHostConnectException]]
然后,编译器评估 classOf[RetryException] :: tmp1。类型推断尝试统一左侧和右侧的类型,并提供 List[_ >: RetryException with HttpHostConnectException]
您可能想知道为什么它不能推断 List[Class[Exception]]。这是因为 Class不协变(它是不变的),因此 Class[HttpHostConnectException]Class[RetryException]不是 Class[Exception]的子类型。
现在您可能还认为编译器可以推断出更简单(但不太精确)的 List[AnyRef]类型。但是编译器只是试图尽可能地精确,这在总体上显然非常有用。但是在这种情况下,它将对下一步造成问题。
因此,我们将这个表达式的结果称为 tmp2: List[_ >: RetryException with HttpHostConnectException],看看接下来会发生什么。

最后,编译器评估 classOf[ConnectTimeoutException] :: tmp2

在此, ::的签名要求 classOf[ConnectTimeoutException]RetryException with HttpHostConnectException的子类型(到目前为止,列表元素的类型)。换句话说,需要 ConnectTimeoutException来同时扩展 RetryExceptionHttpHostConnectException,但这显然不是这种情况,因此会出现编译错误

关于scala - scala : classOf[], exceptions and::operator for lists weird behavior,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15247224/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com