go 大小写对导出的影响

2023-12-19 17:07:47 +08:00
 yujianwjj
package inner

type inner struct {
	I int
}

func New() inner {
	return inner{I: 1}
}

package outter

import (
	"testing"
)

func TestGet(t *testing.T) {
	i := inner.New()
	t.Log(i.I)
}

inner 是小写,理论上不应该被外部能访问,但是通过一个大写的函数,却把它暴露出来了。今天第一次看到这个写法,有点惊讶。

之前我一般都是下面两种写法:

package inner

type Inner interface {
	Get() int
}

type inner struct {
	i int
}

func (i *inner) Get() int {
	return i.i
}

func New() Inner {
	return &inner{i: 1}
}
package inner

type Inner struct {
	I int
}

func New() Inner {
	return Inner{I: 1}
}
1808 次点击
所在节点    Go 编程语言
12 条回复
songray
2023-12-19 17:09:58 +08:00
bro, 这就是闭包.
lilei2023
2023-12-19 17:13:06 +08:00
虽然不太懂,感觉类似闭包
body007
2023-12-19 17:54:30 +08:00
复制某个 GPT 的回答。

非导出类型包含导出字段的应用场景是合法的。这种情况通常出现在需要将结构体值传递给其他包以进行处理的情况下。为了让其他包能够访问字段,这些字段必须是导出的,但结构体类型本身可以保持为非导出。

举个例子,假设你想要生成一个 JSON 响应。你可以创建一个非导出的结构体,然后为了能够使用 `encoding/json` 包,结构体的字段必须是导出的。例如:

```go
type response struct {
Success bool `json:"success"`
Message string `json:"message"`
Data string `json:"data"`
}

func myHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
resp := &response{
Success: true,
Message: "OK",
Data: "some data",
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
// 处理错误
}
}
```

在这个例子中,`response` 结构体是非导出的,但它包含了导出的字段。这使得我们可以在 `myHandler` 函数中创建 `response` 结构体的实例,并将其传递给 `encoding/json` 包来生成 JSON 响应。

总的来说,非导出类型包含导出字段的应用场景通常出现在需要将结构体值传递给其他包以进行处理的情况下。
zizon
2023-12-19 17:56:06 +08:00
因为 inner.New 是 exported 的.

类似于 func New() interface{}

加上导出不导出本来就是个编译器的约束.
所以 i.I 也是可以的(I exported).

你可以去提个 issue 争议下算不算 bug...
zizon
2023-12-19 17:58:28 +08:00
说可以是 bug 的原因是它形式上略不同于
func New() interface{}

因为有一个编译期确切的返回类型.
zizon
2023-12-19 18:00:55 +08:00
说不是 bug 的原因在于它算是一种 feature.

需要暴露一个类型/接口,但又不想添加显式的约束(interface type/struct type).
同时又不想给个没有类型约束的 interface{}.

所以等价于一个 public 的接口返回一个不可修改/不可外部构造的类型.
nagisaushio
2023-12-19 18:08:43 +08:00
@body007 你这回答和楼主的问题没有关系,楼主没有在问和字段相关的内容。建议不要瞎贴 GPT 的内容,会被站长枪毙。
body007
2023-12-19 18:12:43 +08:00
@nagisaushio 就是要讨论字段 I 被导出,外部可以调用,而 inner 类型不是导出的情况,我只是列出了一种场景吧。
thevita
2023-12-19 18:15:20 +08:00
不能导出的是 inner 这个类型

func New() inner {} , 这个函数是 导出的, 这里的可以理解成一个复合类型

就像

struct Struct {
inner inner
}

这个 Struct 被导出了,但它作为一个复合类型,内部引用了 inner 一样.
leonshaw
2023-12-19 18:18:35 +08:00
导出不导出指的是 identifier
kiripeng
2023-12-19 18:19:44 +08:00
写成函数是为了做约束,比如 邮件不愿意外面的得到准确做了模糊处理 xxx**@gmail.com
hxtheone
2023-12-19 18:21:19 +08:00
虽然这个做法能被编译通过而且也有一定的使用场景, 但是感觉是因为支持闭包留下的一个口子, 如果开了 linter 的话都会被提醒一句 'exported func Outer returns unexported type main.inner, which can be annoying to use’, 像我这种强迫症肯定是会把 inner 改掉的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1001713

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX