首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go语言标识符是否可导出冷门知识点[译]

Go语言标识符是否可导出冷门知识点[译]

作者头像
数据小冰
发布2025-04-01 16:49:22
发布2025-04-01 16:49:22
12200
代码可运行
举报
文章被收录于专栏:数据小冰数据小冰
运行总次数:0
代码可运行
引言

在Go语言中,类型名称、变量或者函数名首字母大写,表示其是可导出的,对于这个知识点我们都不陌生。例如,如果一个函数名首字母是大写的,我们称之为公有方法,相反如果首字母是小写,则称为私有方法。其实用“公有”和“私有”来描述并不是很准确,准确的理解是:当一个标识符可以被导出时(首字母大写),表示可以被其他包直接访问,当一个标识符不能被导出时(首字母小写),则无法被其他包 直接 访问。📢标识符不能被导出并不意味着它完全不能在包外被访问,只是不能直接访问。本文将介绍在Go语言中关于标识符是否导出的一些冷门知识,欢迎点赞收藏。

直接访问

下面通过一个可导出类型举例说明, 项目目录结构如下,在test文件夹下的exportedtypes1.go中定义了一个 AlertCounter类型,它虽然是基于int的一个别名,但完全是一个新类型,并且类型的首字母A大写,表明它可以直接导出在其他包中使用。

代码语言:javascript
代码运行次数:0
运行
复制
package counters

type AlertCounter int

在main包中编写代码进行验证,代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
package main

import (
 "fmt"
 "identifier/test"
)

func main() {
 counter := counters.AlertCounter(10)
 fmt.Printf("Counter: %d\n", counter)
}

编译运行输出:Counter: 10, 没有任何问题。

现在将类型AlertCounter首字母改为小写的a, 即不可导出,看看会出现什么问题。

代码语言:javascript
代码运行次数:0
运行
复制
package counters

type alertCounter int

可以看到,编辑器直接提示错误。强行编译会失败,提示未找到 counters.alertCounter 类型定义。

代码语言:javascript
代码运行次数:0
运行
复制
./main.go:9:22: undefined: counters.alertCounter

尽管我们不能直接访问 alertCounter 类型,因为它是不可导出的,但是有一种方法可以在包外创建并且使用此未导出类型的变量,实现如下。

在 counters 包中定义一个可导出函数 NewAlertCounter,该函数返回值为 alertCounter 类型。

代码语言:javascript
代码运行次数:0
运行
复制
package counters

type alertCounter int

func NewAlertCounter(value int) alertCounter {
 return alertCounter(value)
}

在main中调用上述代码,可以正常编译,运行输出10。

代码语言:javascript
代码运行次数:0
运行
复制
func main() {
 counter := counters.NewAlertCounter(10)
 fmt.Printf("Counter: %d\n", counter)
}

结构体内嵌不可导出类型

同理对于结构体类型,如果结构体中的字段首字母是大写的,表示其是可导出的能够在包外直接访问,如果首字母是小写的。是不可导出的不能直接在包外访问。

下面的 Dog 结构体含有两个可导出字段和一个不可导出字段,如果在main函数中给age赋值,会产生错误。

代码语言:javascript
代码运行次数:0
运行
复制
package animals

type Dog struct {
 Name         string
 BarkStrength int
 age          int
}

main函数中定义一个Dog类型变量,然后打印。

编译会报错:

代码语言:javascript
代码运行次数:0
运行
复制
go run main.go                               
./main.go:12:3: unknown field age in struct literal of type animals.Dog

现在对Dog结构体做点调整,拆分成如下两个结构体,内嵌一个animal。

代码语言:javascript
代码运行次数:0
运行
复制
type animal struct{
 Name string
 Age int
}

type Dog struct{
 animal
 BarkStrength int
}

由于结构体animal首字母小写是不可导出类型,所以在main包中无法引用,产生错误。

但是可以通过下面的方法对不可导出类型animal中的Name和Age进行初始。

代码语言:javascript
代码运行次数:0
运行
复制
func main() {
 dog := animals.Dog{
  BarkStrength: 10,
 }
 dog.Name = "Chole"
 dog.Age = 1
}
标准库

Go标准库time包中的 Time 结构体是一个很好的范例,该结构体中的字段是小写即不可导出,从而隐藏内部实现。达到封装性、安全性和兼容性目的。

  • 封装性:外部代码无法直接修改Time结构中的字段
  • 安全性:防止外部代码赋值一些不符合规范的值
  • 兼容性:内部实现可以随时更改,但不影响外部代码使用
代码语言:javascript
代码运行次数:0
运行
复制
type Time struct {
 wall uint64
 ext  int64

 loc *Location
}

只能通过Time提供的方法操作Time对象,例如 Time.Add进行时间加减,Time.Format进行格式化,Time.Compare进行时间比较。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据小冰 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
    • 直接访问
  • 结构体内嵌不可导出类型
  • 标准库
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档