V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
yujianwjj
V2EX  ›  Go 编程语言

go 大小写对导出的影响

  •  
  •   yujianwjj · 2023-12-19 17:07:47 +08:00 · 1807 次点击
    这是一个创建于 365 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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}
    }
    
    12 条回复    2023-12-19 18:21:19 +08:00
    songray
        1
    songray  
       2023-12-19 17:09:58 +08:00
    bro, 这就是闭包.
    lilei2023
        2
    lilei2023  
       2023-12-19 17:13:06 +08:00
    虽然不太懂,感觉类似闭包
    body007
        3
    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
        4
    zizon  
       2023-12-19 17:56:06 +08:00
    因为 inner.New 是 exported 的.

    类似于 func New() interface{}

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

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

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

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

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

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

    就像

    struct Struct {
    inner inner
    }

    这个 Struct 被导出了,但它作为一个复合类型,内部引用了 inner 一样.
    leonshaw
        10
    leonshaw  
       2023-12-19 18:18:35 +08:00
    导出不导出指的是 identifier
    kiripeng
        11
    kiripeng  
       2023-12-19 18:19:44 +08:00
    写成函数是为了做约束,比如 邮件不愿意外面的得到准确做了模糊处理 xxx**@gmail.com
    hxtheone
        12
    hxtheone  
       2023-12-19 18:21:19 +08:00 via iPhone
    虽然这个做法能被编译通过而且也有一定的使用场景, 但是感觉是因为支持闭包留下的一个口子, 如果开了 linter 的话都会被提醒一句 'exported func Outer returns unexported type main.inner, which can be annoying to use’, 像我这种强迫症肯定是会把 inner 改掉的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2706 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 15:28 · PVG 23:28 · LAX 07:28 · JFK 10:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.