英文:
Why does Go panic() take interface{} instead of ...interface{} as argument?
问题
我注意到panic
函数接受interface{}
作为参数,而fmt.Print
等函数接受...interface{}
。如果panic
也接受...interface{}
作为参数,会不会更方便呢?
为什么Go语言的作者将panic
定义为func panic(v interface{})
,而不是像fmt
那样定义为func panic(v ...interface{})
?
英文:
I noticed panic
takes interface{}
as an argument, while fmt.Print
and the likes take ...interface{}
. Wouldn't it be more convenient if panic
took ...interface{}
as well?
Why did the Go authors define panic
as func panic(v interface{})
rather than func panic(v ...interface{})
(like they did with fmt
)?
答案1
得分: 5
panic
在最初并不只接受一个参数。你可以追溯到2010年3月30日的实现,提交记录01eaf78中添加了panic
和recover
(在运行时中仍未实现)。
> 主要的语义变化是强制panic
只接受一个参数。
在提交记录5bb29fb中修复了规范,并且提交记录00f9f0c说明了在多个参数之前panic
的用法:
src/pkg/bufio/bufio.go
b, err := NewWriterSize(wr, defaultBufSize)
if err != nil {
// 不可能发生- defaultBufSize是有效的大小
- panic("bufio: NewWriter: ", err.String())
+ panic(err)
}
这是根据2010年3月25日的提案:
> 我们不希望鼓励像Java这样的语言中错误和异常混淆的情况。
>
> 相反,该提案对defer
的定义进行了轻微更改,并使用了一些运行时函数,以提供一种处理真正异常情况的清晰机制。
>
> 在发生恐慌时,如果延迟函数调用了recover
,recover
会返回传递给panic
的值并停止恐慌。
在其他任何时间,或者在被延迟调用的函数内部,recover
返回nil
。
在停止恐慌之后,延迟调用可以使用新的参数或相同的参数继续恐慌。
或者,延迟调用可以编辑其外部函数的返回值,例如返回一个错误。
在这些不同的情况下,处理一个传递的值似乎比处理可变数量的参数更容易(特别是在C中实现recover
时)。
英文:
panic
didn't take just one argument at first.
You can trace back the one argument implementation back to 30th March 2010:
commit 01eaf78 gc: add panic
and recover
(still unimplemented in runtime)
> main semantic change is to enforce single argument to panic.
The spec is fixed in commit 5bb29fb, and commit 00f9f0c illustrates how panic could took before multiple arguments:
src/pkg/bufio/bufio.go
b, err := NewWriterSize(wr, defaultBufSize)
if err != nil {
// cannot happen - defaultBufSize is valid size
- panic("bufio: NewWriter: ", err.String())
+ panic(err)
}
That follows a proposal from March 25th, 2010:
> We don't want to encourage the conflation of errors and exceptions that occur in languages such as Java.
>
> Instead, this proposal uses a slight change to the definition of defer and a couple of runtime functions to provide a clean mechanism for handling truly exceptional conditions.
>
> During panicking, if a deferred function invocation calls recover, recover returns the value passed to panic and stops the panicking.
At any other time, or inside functions called by the deferred call, recover returns nil.
After stopping the panicking, a deferred call can panic with a new argument, or the same one, to continue panicking.
Alternately, the deferred call might edit the return values for its outer function, perhaps returning an error.
In those various scenario, dealing with one value to pass around seems easier than dealing with an variable number of arguments (especially when it comes to implement recover
in C).
答案2
得分: 2
因为您传递给panic
的值是您想要引发的值,并且可以使用recover
进行检索。拥有多个panic值并没有太多意义。
package main
import "fmt"
func main() {
defer func() {
if v := recover(); v != nil {
fmt.Println(v.(int))
}
}()
panic(3)
}
使用recover值的示例:
有关panic和recover的真实示例,请参阅Go标准库中的json包。它使用一组递归函数解码JSON编码的数据。当遇到格式错误的JSON时,解析器调用panic来展开堆栈到顶级函数调用,该函数从panic中恢复并返回适当的错误值(请参阅decode.go中decodeState类型的'error'和'unmarshal'方法)。
来源:http://blog.golang.org/defer-panic-and-recover
英文:
Because the value you pass to panic
is a value you want to panic with and can be retrieved using recover
. Having multiple panic values doesn't really make sense.
package main
import "fmt"
func main() {
defer func() {
if v := recover(); v != nil {
fmt.Println(v.(int))
}
}()
panic(3)
}
Example on using recover values:
> For a real-world example of panic and recover, see the json package
> from the Go standard library. It decodes JSON-encoded data with a set
> of recursive functions. When malformed JSON is encountered, the parser
> calls panic to unwind the stack to the top-level function call, which
> recovers from the panic and returns an appropriate error value (see
> the 'error' and 'unmarshal' methods of the decodeState type in
> decode.go).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论