Unit): T? { try { block() } catch (ex: -6ren">
gpt4 book ai didi

generics - 如何规避 Kotlin 的限制 "Type parameter is forbidden for catch parameter"

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

我定义了以下函数:

inline fun <T> T.tryTo(block: T.() -> Unit): T? {
try {
block()
} catch (ex: IllegalArgumentException) {
return this
}
return null
}

目的是在对象上构建一系列尝试操作,例如:
val input: String = getInput();

input.tryTo /* treat as a file name and open the file */ {
Desktop.getDesktop().open(File(this))
}?.tryTo /* treat as a number */ {
try {
doSomethingWithTheNumber(parseInt(this))
} catch (ex: NumberFormatException) {
throw IllegalArgumentException()
}
}?.tryTo {
println("All options tried, none worked out. Don't know how to treat this input.")
}

到目前为止,效果很好。

但是,正如您在 tryTo-block 中间(“视为数字”)中所见,将“预期”异常重新抛出为 IllegalArgumentException 以保持架构正常工作是不方便的。最好写成:
val input: String = getInput();

input.tryTo<IllegalArgumentException> /* treat as a file name and open the file */ {
Desktop.getDesktop().open(File(this))
}?.tryTo<NumberFormatException> /* treat as a number */ {
doSomethingWithTheNumber(parseInt(this))
}?.tryTo<Exception> {
println("All options tried, none worked out. Don't know how to treat this input.")
}

所以,我将函数 tryTo 重写为:
inline fun <T, X: Exception> T.tryTo(block: T.() -> Unit): T? {
try {
block()
} catch (ex: X) {
return this
}
return null
}

不幸的是,后者不能编译:“类型参数被禁止用于捕获参数”。

如何规避这个限制?

附录:

现在我已经做到了:
inline fun <T, reified X: Exception> T.tryTo(block: T.() -> Unit): T? {
try {
block()
} catch (ex: Exception) {
return if (ex is X) this else throw ex
}
return null
}

但我对此仍然不满意,因为它要求我指定 两者 显式类型(“类型推断失败...”/“需要 2 个类型参数...”):
input.tryTo<String, IllegalArgumentException> /* treat as a file in the stapel-directory */ {
...
}

尽管第一个类型参数很明显可以从接收器对象推断出来。

最佳答案

我认为如果您只是使类型参数具体化,这是可能的,但显然不是。我确实找到了 source在这个检查中,对于 catch 子句中的任何类型的类型参数,无论是否具体化,它都非常明显地出错。

添加这些检查的提交消息引用了 this issue - 显然带有类型参数的 catch 子句捕获了所有抛出的 Exception实例,并以 ClassCastException 崩溃如果异常不是指定的类型。

您的案例可能的解决方法来自 this answer对于类似的 Java 问题 - 如果泛型类型被具体化,您可以检查抛出的异常是否属于该特定类型,我相信这使该函数成为您正在寻找的:

inline fun <T, reified X : Exception> T.tryTo(block: T.() -> Unit): T? {
try {
block()
} catch (ex: Exception) {
if (ex is X) {
return this
}
}
return null
}

尽管调用站点变得非常难看,因为如果函数调用有两个类型参数,则不能只指定它的第二个类型参数:
val input: String = getInput()

input.tryTo<String, IllegalArgumentException> /* treat as a file name and open the file */ {
Desktop.getDesktop().open(File(this))
}?.tryTo<String, NumberFormatException> /* treat as a number */ {
doSomethingWithTheNumber(parseInt(this))
}?.tryTo<String, Exception> {
println("All options tried, none worked out. Don't know how to treat this input.")
}

一个比上面更好的替代方案,更接近原始的 Java 答案:
inline fun <T> T.tryTo(exceptionType: KClass<out Exception>, block: T.() -> Unit): T? {
try {
block()
} catch (ex: Exception) {
if (exceptionType.isInstance(ex)) {
return this
}
}
return null
}

KClass像这样传入的实例:
input.tryTo(IllegalArgumentException::class) /* treat as a file name and open the file */ {
Desktop.getDesktop().open(File(this))
}?.tryTo(NumberFormatException::class) /* treat as a number */ {
doSomethingWithTheNumber(parseInt(this))
}?.tryTo(Exception::class) {
println("All options tried, none worked out. Don't know how to treat this input.")
}

关于generics - 如何规避 Kotlin 的限制 "Type parameter is forbidden for catch parameter",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49984075/

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