Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 根据返回参数(如类型断言)的数量更改行为_Go - Fatal编程技术网

Go 根据返回参数(如类型断言)的数量更改行为

Go 根据返回参数(如类型断言)的数量更改行为,go,Go,我一直在学习Go,我特别感兴趣的一件事是类型断言的行为根据捕获的返回值的多少而改变: var i interface{} = "hello" val, ok := i.(int) // All good fmt.Println(val, ok) val = i.(int) // Panics fmt.Println(val) 这种模式对于用户定义的函数非常有用。用户要么显式获取“ok”第二个返回值,要么使用下划线忽略它。在这两种情况下,他们都明确表示,他们意识到功能可能会失败。然而,如果他

我一直在学习Go,我特别感兴趣的一件事是类型断言的行为根据捕获的返回值的多少而改变:

var i interface{} = "hello"

val, ok := i.(int) // All good
fmt.Println(val, ok)

val = i.(int) // Panics
fmt.Println(val)
这种模式对于用户定义的函数非常有用。用户要么显式获取“ok”第二个返回值,要么使用下划线忽略它。在这两种情况下,他们都明确表示,他们意识到功能可能会失败。然而,如果他们只得到一个返回值,它可能会默默地失败。因此,如果用户没有检查错误(如果错误“永远”不会发生),那么恐慌或类似的情况似乎是合理的。我假设这就是语言开发人员使类型断言以这种方式工作的逻辑

但当我试图找出如何做到这一点时,我一无所获。我知道类型断言不是一个实际的函数。许多具有多个返回值的语言无法检查实际使用了多少个返回值(我只知道MATLAB),但是,大多数语言都没有使用类型断言所演示的行为


那么,是否可能,如果可能,如何实现?如果没有,那么尽管内置类型断言可以实现这种行为,但这种行为被排除在外是否有特殊原因?

遗憾的是,它们不能用于正常函数中。据我所知,只有类型断言、映射值访问和范围允许它

通常,当您想要有一个带有一个可选错误参数和第二个可选错误参数的函数时,您可以将其命名为

func DoSomething() (string, error) {...} // i will return an error
func MustDoSomething() string {...}  // i will panic
例如,

这个答案:by@christian提供了关于如何模拟“结果计数重载”模式的最佳实用建议

我的目标是解决问题的另一部分,这一部分:“但当我试图找出如何做到这一点时,我什么也没有发现”

下面解释如何对Go类型断言执行此操作


Go中的类型断言调用的行为就好像它们是根据结果的数量重载的一样

然而,许多方法和操作符仍然存在

看看Go的实现,下面是基于结果数量的类型断言过载的原因:

  • Go编译器提供了这些内置操作所特有的特殊处理
对于类型断言的内置概念,会发生这种特殊的分派,因为编译器正在划分出对非内置代码可用的特殊逻辑

Go编译器和运行时是用Go编写的。这使我很容易发现编译器是解释这种行为的关键

请看一下编译器的这一部分:

代码注释已经揭示了很多:

// dottype generates SSA for a type assertion node.
// commaok indicates whether to panic or return a bool.
// If commaok is false, resok will be nil.
我们可以通过使用调试器来逐步完成某些类型断言代码,从而更进一步

比如说。具体而言,这些行:

object_as_closer_hardstop     := thing.(io.Closer) // will panic!!
object_as_closer,      ok     := thing.(io.Closer)
(如果是,则)如果使用调试器单步执行第一个类型断言,则在Go运行时将得到以下代码:

如果您进入第二个步骤,您将在以下位置结束:

在第438行,您可以看到
func断言2i
(带有一个返回值)。稍微低一点,在第454行,您可以看到
assert2i2
。请注意,这两个函数的名称几乎相同,但并不完全相同

第二个函数的名称末尾有一个尾随
2
。该函数还有两个返回结果

正如我们预期的那样:

  • 我可以恐慌,但是
  • 不能
(查看
iface.go
中的函数体,并注意其中包含的
panic

assert2i
assert2i2
遵守我们期望的重载规则。如果它们只是在结果数量上有所不同,那么我们这些从源代码编译Go的人将无法编译Go运行时,因为编译器错误,例如“assert2i redecared”

该语言的用户通常不知道这些内置运行时函数,因此表面上看,两行代码似乎调用了相同的函数:

object_as_closer_hardstop     := thing.(io.Closer) // will panic!!
object_as_closer,      ok     := thing.(io.Closer)
但是,在编译时,编译器会根据是否找到“commaok”案例进行分支:

我们自己的最终用户代码无法修改Go的lexing/parsing/AST walking,以便基于“commaok”分派不同风格的函数


不管是好是坏,这就是为什么用户编写的代码不能利用这种模式。

您不能编译分配了错误数量的返回值的代码,所以我不确定您的建议是什么。错误不是“永远不会发生”的情况,错误会一直返回并处理,即使在正常情况下也是如此。