嵌入式错误是否被导出?

huangapple go评论72阅读模式
英文:

Is an embedded error exported?

问题

根据Go语言规范,我可以在结构体中嵌入一个类型。

对于error接口有一个奇怪的情况。它的首字母没有大写,所以我认为它不是作为一个类型导出的。但它是由语言定义的。所以如果我有一个如下的结构体:

package foo

type Err struct {
    error
}

嵌入的error是否被导出?Err是否满足error接口?

我可以从另一个包中访问它吗?也就是下面的代码是否正确?

package main

import "errors"
import "fmt"
import "foo"

func main() {
    e := foo.Err{}
    e.error = errors.New("Hello world!") // 这样可以吗?
    fmt.Println(e.Error())
}
英文:

According to the Go language spec, I can embed a type in a struct.

There is a weird case with the error interface. It is not uppercased, so I assume it is not exported as a type. But it is defined by the language. So if I have a struct like this:

package foo

type Err struct {
    error
}

is the embedded error exported? Does Err satisfy the error interface?

Can I access it from another package, i.e. is the following ok?

package main

import "errors"
import "fmt"
import "foo"

func main() {
    e := foo.Err{}
    e.error = errors.New("Hello world!") // is this okay?
    fmt.Println(e.Error())
}

答案1

得分: 5

当你将一个error接口嵌入到一个结构体中时,基本上是在它中添加了一个名为error、类型为error的字段。

因为它是嵌入的,所以你的结构体现在也实现了它的所有方法。这意味着你的结构体满足了error接口,你可以在它上面调用Error()方法,或者直接将它传递给Println,它会将其类型断言为error并为你调用Error()方法。https://play.golang.org/p/0VxUUX2l-z

显然,由于字段名为error,它是不可导出的。但是,该结构体仍然满足error接口,因为它有Error()方法。

有趣的结果是,如果你不初始化该字段,Println会引发恐慌,因为它将尝试在nil上调用Error()方法。https://play.golang.org/p/XctFgKZI-K

英文:

When you embed an error interface into a struct, basically, you add a field named error with type error to it.

Because it's embedded your struct now also implements all of it's methods. That means your struct satisfies the error interface and you can call Error() on it or just pass it to Println as it is and it will type assert it into error and call Error() for you https://play.golang.org/p/0VxUUX2l-z

Obviously, because field is named error it's not exported. But the struct still satisfies the error interface because it has Error() method.

Interesting consequence of this is that if you don't initialize the field Println will panic because it will try to call Error() on nil https://play.golang.org/p/XctFgKZI-K

答案2

得分: 0

e := foo.Err{}
e.error = errors.New("你好,世界!") // 错误

这会导致错误,因为e.error在包外部是不可访问的。
如果你需要设置这个字段,你可以声明一个构造函数:

func NewError(err error) *Error {
	return &Error{error: err}
}

但是如果你真的需要导出这个字段,这仍然是可能的:你可以声明一个类型别名:

type Error struct {
	Err
}
type Err = error

然后你可以从包外部访问e.Err字段。

英文:
e := foo.Err{}
e.error = errors.New("Hello world!") // error

This will cause an error since e.error is not accessible from outside package.
If you need to set this field, you may declare a constructor:

func NewError(err error) *Error {
	return &Error{error: err}
}

But if you really need to export this field, this is still possible: you may declare a type alias:

type Error struct {
	Err
}
type Err = error

Then you may access e.Err field from outside package.

huangapple
  • 本文由 发表于 2016年2月28日 09:35:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/35677690.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定