文章目录

  • 1、常量(const关键字)
    • 1.1、概念
    • 1.2、iota 常量生成器
    • 1.3、无类型常量
  • 2、枚举(const和iota枚举)
    • 2.1、概念
    • 2.2、将枚举值转换为字符串
  • 3、注释(定义及使用)
    • 3.1、定义
    • 3.2、示例
    • 3.3、godoc 工具
  • 4、类型别名(type关键字)
    • 4.1、区分类型别名与类型定义
    • 4.2、非本地类型不能定义方法
    • 4.3、在结构体成员嵌入时使用别名
  • 5、指针
    • 5.1、概念
      • 5.1.1、Go的指针
      • 5.1.2、C/C++中的指针
    • 5.2、认识指针地址和指针类型
    • 5.3、从指针获取指针指向的值
    • 5.4、使用指针修改值
    • 5.5、创建指针的另一种方法——new() 函数
    • 5.6、示例:使用指针变量获取命令行的输入信息

1、常量(const关键字)

1.1、概念

Go语言中的常量使用关键字 const 定义,用于存储不会改变的数据,常量是在编译时被创建的,即使定义在函数内部也是如此,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。由于编译时的限制,定义常量的表达式必须为能被编译器求值的常量表达式。
常量的定义格式和变量的声明语法类似:const name [type] = value,例如:

const pi = 3.14159 // 相当于 math.Pi 的近似值

在Go语言中,你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。

  • 显式类型定义: const b string = “abc”
  • 隐式类型定义: const b = “abc”

常量的值必须是能够在编译时就能够确定的,可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。

  • 正确的做法:const c1 = 2/3
  • 错误的做法:const c2 = getNumber() // 引发构建错误: getNumber() 用做值

可以批量生成,例如:

const (a = 1bc = 2d
)
fmt.Println(a, b, c, d) // "1 1 2 2"

如果只是简单地复制右边的常量表达式,其实并没有太实用的价值。但是它可以带来其它的特性,那就是 iota 常量生成器语法。

1.2、iota 常量生成器

常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加一。示例:

type Weekday int
const (Sunday Weekday = iotaMondayTuesdayWednesdayThursdayFridaySaturday
)

周日将对应 0,周一为 1,以此类推。

1.3、无类型常量

Go语言的常量有个不同寻常之处。虽然一个常量可以有任意一个确定的基础类型,例如 int 或 float64,或者是类似 time.Duration 这样的基础类型,但是许多常量并没有一个明确的基础类型。

编译器为这些没有明确的基础类型的数字常量提供比基础类型更高精度的算术运算,可以认为至少有 256bit 的运算精度。这里有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。

通过延迟明确常量的具体类型,不仅可以提供更高的运算精度,而且可以直接用于更多的表达式而不需要显式的类型转换。

math.Pi 无类型的浮点数常量,可以直接用于任意需要浮点数或复数的地方:

var x float32 = math.Pi
var y float64 = math.Pi
var z complex128 = math.Pi

如果 math.Pi 被确定为特定类型,比如 float64,那么结果精度可能会不一样,同时对于需要 float32 或 complex128 类型值的地方则需要一个明确的强制类型转换:

const Pi64 float64 = math.Pi
var x float32 = float32(Pi64)
var y float64 = Pi64
var z complex128 = complex128(Pi64)

对于常量面值,不同的写法可能会对应不同的类型。例如 0、0.0、0i 和 \u0000 虽然有着相同的常量值,但是它们分别对应无类型的整数、无类型的浮点数、无类型的复数和无类型的字符等不同的常量类型。同样,true 和 false 也是无类型的布尔类型,字符串面值常量是无类型的字符串类型。

2、枚举(const和iota枚举)

2.1、概念

Go语言现阶段没有枚举类型,但是可以使用 const 常量的 iota 来模拟枚举类型,如下:

type Weapon int
const (Arrow Weapon = iota    // 开始生成枚举值, 默认为0ShurikenSniperRifleRifleBlower
)
// 输出所有枚举值
fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)
// 使用枚举类型并赋初值
var weapon Weapon = Blower
fmt.Println(weapon)

代码输出如下:

0 1 2 3 4
4

iota高级用法,如:

const (FlagNone = 1 << iotaFlagRedFlagGreenFlagBlue
)
fmt.Printf("%d %d %d\n", FlagRed, FlagGreen, FlagBlue) // 2 4 8
fmt.Printf("%b %b %b\n", FlagRed, FlagGreen, FlagBlue) // 10 100 1000

2.2、将枚举值转换为字符串

直接看代码:

package main
import "fmt"
// 声明芯片类型
type ChipType int
const (None ChipType = iotaCPU    // 中央处理器GPU    // 图形处理器
)
func (c ChipType) String() string {switch c {case None:return "None"case CPU:return "CPU"case GPU:return "GPU"}return "N/A"
}
func main() {// 输出CPU的值并以整型格式显示fmt.Printf("%s %d", CPU, CPU) // CPU 1
}

3、注释(定义及使用)

3.1、定义

Go语言的注释和C/C++的注释一样。主要分成两类,分别是单行注释和多行注释。

  • 单行注释简称行注释,是最常见的注释形式,可以在任何地方使用以//开头的单行注释;
  • 多行注释简称块注释,以/开头,并以/结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。

3.2、示例

单行注释的格式如下所示

//单行注释

多行注释的格式如下所示

/*
第一行注释
第二行注释
...
*/

3.3、godoc 工具

godoc 工具会从 Go 程序和包文件中提取顶级声明的首行注释以及每个对象的相关注释,并生成相关文档,也可以作为一个提供在线文档浏览的 web 服务器,Go语言官网(https://golang.google.cn/)就是通过这种形式实现的。

go get 命令来获取 godoc 工具。如果golang的墙太厚,可以用github:“https://github.com/golang/tools.git”

go get golang.org/x/tools/cmd/godoc

可以直接使用,在命令行输入:godoc -http=:6060
在浏览器输入“http://localhost:6060/pkg/”,可以看到你所以Gopath目录下的src下的项目:

举例看一下某一个项目的doc,如下:

4、类型别名(type关键字)

类型别名是 Go 1.9 版本添加的功能,主要用于解决代码升级、迁移中存在的类型兼容性问题。
在 Go 1.9 版本之前定义内建类型的代码是这样写的:

type byte uint8
type rune int32

而在 Go 1.9 版本之后变为:

type byte = uint8
type rune = int32

这个修改就是配合类型别名而进行的修改。

4.1、区分类型别名与类型定义

定义类型别名的写法为:type TypeAlias = Type。类型别名规定:TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型。示例代码:

package main
import ("fmt"
)
// 将NewInt定义为int类型
type NewInt int
// 将int取一个别名叫IntAlias
type IntAlias = int
func main() {// 将a声明为NewInt类型var a NewInt// 查看a的类型名fmt.Printf("a type: %T\n", a)// 将a2声明为IntAlias类型var a2 IntAlias// 查看a2的类型名fmt.Printf("a2 type: %T\n", a2)
}

结果:

a type: main.NewInt
a2 type: int

结果显示 a 的类型是 main.NewInt,表示 main 包下定义的 NewInt 类型,a2 类型是 int,IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。

4.2、非本地类型不能定义方法

能够随意地为各种类型起名字,并不意味着可以在自己包里为这些类型任意添加方法,看代码:

package main
import ("time"
)
// 定义time.Duration的别名为MyDuration
type MyDuration = time.Duration... ...

这样的代码,编译会报错,

cannot define new methods on non-local type time.Duration

解决方案有两种:

  • 1、将第 8 行修改为 type MyDuration time.Duration,也就是将 MyDuration 从别名改为类型;
  • 2、将 MyDuration 的别名定义放在 time 包中。

4.3、在结构体成员嵌入时使用别名

当类型别名作为结构体嵌入的成员时,情况如下:

package main
import ("fmt""reflect"
)
// 定义商标结构
type Brand struct {}
// 为商标结构添加Show()方法
func (t Brand) Show() {}
// 为Brand定义一个别名FakeBrand
type FakeBrand = Brand
// 定义车辆结构
type Vehicle struct {// 嵌入两个结构FakeBrandBrand
}
func main() {// 声明变量a为车辆类型var a Vehicle// 指定调用FakeBrand的Showa.FakeBrand.Show()// 取a的类型反射对象ta := reflect.TypeOf(a)// 遍历a的所有成员for i := 0; i < ta.NumField(); i++ {// a的成员信息f := ta.Field(i)// 打印成员的字段名和类型fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.Name())}
}

结果如下:

FieldName: FakeBrand, FieldType: Brand
FieldName: Brand, FieldType: Brand

5、指针

5.1、概念

5.1.1、Go的指针

Go语言为程序员提供了控制数据结构指针的能力,但并不能进行指针运算。Go语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这对于构建运行良好的系统是非常重要的。指针对于性能的影响不言而喻,如果你想要做系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。

指针在Go语言中可以被拆分为两个核心概念:

  • 类型指针,允许对这个指针类型的数据进行修改,传递数据可以直接使用指针,无须拷贝数据,类型指针不能进行偏移和运算。
  • 切片,由指向起始元素的原始指针、元素数量和容量组成。

受益于这样的约束和拆分,Go语言的指针类型变量即拥有指针高效访问的特点,又不会发生指针偏移,从而避免了非法修改关键性数据的问题。同时,垃圾回收也比较容易对不会发生偏移的指针进行检索和回收。

切片比原始指针具备更强大的特性,而且更为安全。切片在发生越界时,运行时会报出宕机,并打出堆栈,而原始指针只会崩溃。

5.1.2、C/C++中的指针

说到 C/C++ 中的指针,会让许多人谈虎色变,尤其是对指针的偏移、运算和转换。

其实,指针是 C/C++ 语言拥有极高性能的根本所在,在操作大块数据和做偏移时即方便又便捷。因此,操作系统依然使用C语言及指针的特性进行编写。

C/C++ 中指针饱受诟病的根本原因是指针的运算和内存释放,C/C++ 语言中的裸指针可以自由偏移,甚至可以在某些情况下偏移进入操作系统的核心区域,我们的计算机操作系统经常需要更新、修复漏洞的本质,就是为解决指针越界访问所导致的“缓冲区溢出”的问题。

要明白指针,需要知道几个概念:指针地址、指针类型和指针取值,下面将展开详细说明。

5.2、认识指针地址和指针类型

一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。指针变量通常缩写为 ptr。

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用在变量名前面添加&操作符(前缀)来获取变量的内存地址(取地址操作),格式:

ptr := &v    // v 的类型为 T

其中 v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为*T,称做 T 的指针类型,*代表指针。
举例:

package main
import ("fmt"
)
func main() {var cat int = 1var str string = "banana"fmt.Printf("%p %p", &cat, &str)
}

结果:

0xc042052088 0xc0420461b0

提示:变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址。

5.3、从指针获取指针指向的值

当使用&操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*操作符,也就是指针取值,代码如下:

package main
import ("fmt"
)
func main() {// 准备一个字符串类型var house = "Malibu Point 10880, 90265"// 对字符串取地址, ptr类型为*stringptr := &house// 打印ptr的类型fmt.Printf("ptr type: %T\n", ptr)// 打印ptr的指针地址fmt.Printf("address: %p\n", ptr)// 对指针进行取值操作value := *ptr// 取值后的类型fmt.Printf("value type: %T\n", value)// 指针取值后就是指向变量的值fmt.Printf("value: %s\n", value)
}

结果:

ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265

取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:

  • 对变量进行取地址操作使用&操作符,可以获得这个变量的指针变量。
  • 指针变量的值是指针地址。
  • 对指针变量进行取值操作使用*操作符,可以获得指针变量指向的原变量的值。

5.4、使用指针修改值

通过指针不仅可以取值,也可以修改值。

前面已经演示了使用多重赋值的方法进行数值交换,使用指针同样可以进行数值交换,代码如下:

package main
import "fmt"
// 交换函数
func swap(a, b *int) {// 取a指针的值, 赋给临时变量tt := *a// 取b指针的值, 赋给a指针指向的变量*a = *b// 将a指针的值赋给b指针指向的变量*b = t
}
func main() {// 准备两个变量, 赋值1和2x, y := 1, 2// 交换变量值swap(&x, &y)// 输出变量值fmt.Println(x, y)
}

运行结果:

2 1

*操作符作为右值时,意义是取指针的值,作为左值时,也就是放在赋值操作符的左边时,表示 a 指针指向的变量。其实归纳起来,*操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值,当操作在左值时,就是将值设置给指向的变量。代码如下:

package main
import "fmt"
func swap(a, b *int) {b, a = a, b
}
func main() {x, y := 1, 2swap(&x, &y)fmt.Println(x, y)
}

结果:

1 2

结果表明,交换是不成功的。上面代码中的 swap() 函数交换的是 a 和 b 的地址,在交换完毕后,a 和 b 的变量值确实被交换。但和 a、b 关联的两个变量并没有实际关联。这就像写有两座房子的卡片放在桌上一字摊开,交换两座房子的卡片后并不会对两座房子有任何影响。

5.5、创建指针的另一种方法——new() 函数

Go语言还提供了另外一种方法来创建指针变量,格式:new(类型)

一般这样写:

str := new(string)
*str = "Go语言教程"
fmt.Println(*str)

new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。

5.6、示例:使用指针变量获取命令行的输入信息

Go语言内置的 flag 包实现了对命令行参数的解析,flag 包使得开发命令行工具更为简单。
提前定义一些命令行指令和对应的变量,并在运行时输入对应的参数,经过 flag 包的解析后即可获取命令行的数据。

package main
// 导入系统包
import ("flag""fmt"
)
// 定义命令行参数
var mode = flag.String("mode", "", "process mode")
func main() {// 解析命令行参数flag.Parse()// 输出命令行参数fmt.Println(*mode)
}

运行:go run main.go --mode=fast
结果:

原理:

Go开发 之 基础语法(常量、枚举、注释、类型别名、指针)相关推荐

  1. Go 语言快速开发入门(基础语法详解,第一节)

    Go 语言快速开发入门(基础语法详解,第一节) 一.基础语法详解,第一节 1.HelloWorld 1.1.代码编写和解释 1.2.go语言注意事项 2.Go 语言的转义字符&&Go ...

  2. 联合、枚举和类型别名 - C++快速入门13

    联合.枚举和类型别名 让编程改变世界 Change the world by program 联合.枚举和类型别名 在 C++ 里还有许多其他类型使我们暂时还没有提到的.除了对象外,C++ 中最重要的 ...

  3. Go开发 之 基础语法(变量的声明、初始化、作用域,匿名变量,多变量赋值,变量逃逸分析)

    文章目录 1.变量的声明 1.1.标准格式 1.2.简短格式 1.3.批量格式 2.变量的初始化 2.1.标准格式 2.2.编译器推导类型的格式 2.3.声明并初始化 3.多个变量同时赋值 4.匿名变 ...

  4. Go开发 之 基础语法(数据类型、类型转换、运算符的优先级)

    文章目录 1.数据类型 1.1.数值类型 1.1.1.整型(整数类型) 1.1.2.浮点型(小数类型) 1.1.3.复数 1.2.bool类型(布尔类型) 1.3.字符串类型 1.3.1.定义字符串 ...

  5. C#基础(201)--常量枚举

    本文知识点: 1.掌握常量的定义和使用方法 2.理解枚举的作用和特点 3.掌握枚举的使用方法 1.1.常量的定义语法 const  数据类型   常量名称  =  值: 1.2.常见错误 1.3常量的 ...

  6. Python 基础语法:从注释到内置函数

    目录 1-注释.变量.输入输出 1.1-注释: 1.1.1-含义 1.1.2-作用 1.1.3-注释类型 1.2-变量与数据类型 1.2.1-变量 1.2.2-定义变量: 1.2.3-变量的命名规则 ...

  7. python保留字分支结构_Python基础语法----缩进、注释、命名与保留字、数据类型、分支语句、函数...

    缩进 -严格明确:缩进是语法的一部分,缩进不正确程序运行错误 -所属关系:表达代码间包含和层次关系的唯一手段 -长度一致:程序内一致即可,一般用4个空格或1个TAB 注释 -用于提高代码可读性的辅助性 ...

  8. VBA 开发学习--基础语法

    MsgBox "开始学习VBA" '提示框Dim str As String '声明str变量是string类型 Let str = "一起来看流星雨" '给变 ...

  9. python的常量变量_Python基础语法-常量与变量

    Python是一门强类型的动态语言. 字面常量,变量没有类型,变量只是在特定的时间指向特定的对象而已,变量所指向的对象是有类型的. 变量:变量在赋值时被创建,它可以是任何对象的引用,但必须在引用前被赋 ...

最新文章

  1. Linux-6.5下 MariaDB-10基于percona-XtraBackup备份工具的原理及配置详解
  2. L3-002 特殊堆栈
  3. 面试官绝杀:系统是如何支撑高并发的?
  4. 怎样编写测试类测试分支_编写干净的测试–从配置开始
  5. matlab库存点仿真教程,基于MATLABSimulink库存系统建模与仿真.doc
  6. 实验楼 linux内核原理与分析,《Linux内核原理与分析》第一周作业 20189210
  7. 前端学习之路-聚美优品注册页面的实现
  8. 2021年第四季度全球消费者信心总体持平,印度仍为全球最高,中国大幅增长,日本仍远低于全球平均水平 | 美通社头条...
  9. 更新安卓系统部分代码
  10. 【经验】VMware|windows更新20H2版本后VMware虚拟机无法开启(禁用Device guard)
  11. linux搭建ftps(vsftpd),java代码测试上传下载
  12. JS邮箱验证_手机号码验证_电话号码验证-正则验证
  13. 51自学网java壁虎,家里有壁虎什么征兆? _ 设计学院_设计软件教程自学网
  14. python做毕设有哪些好的题目?
  15. 用计算机c语言输出你好,编写第一个C语言程序 - Hello World
  16. Redis5.0.x集群搭建
  17. oracle表空间 设置,oracle表空间的设置与管理(代码实例)
  18. 关于开展第六批山东省首版次高端软件申报工作的通知
  19. GPS NMEA协议解析之通用语句
  20. 一招教你免费提取PDF中的文字

热门文章

  1. 五一放一天不调休,你能接受吗?
  2. 云测试 入门 笔记
  3. macOS中快速打开终端
  4. Oracle题目求帮助
  5. 微信小程序学习2022.11.22
  6. 阿里云ECS服务器跨账号迁移
  7. C++查询文本中所有单词出现的频率,并且根据出现次数由多到少依次排列。
  8. XML解析 (JAVA解析xml文件)java+Dom4j+Xpath xml文件解析根据子节点得到父节点 查找校验xml文件中相同的节点属性值 java遍历文件夹解析XML
  9. Chrome 浏览器常用设置及问题(vimium)
  10. 16G内存手机的福音,微信小程序也能建共享相册啦