mirror of
https://github.com/kaka111222333/kaka111222333.github.io.git
synced 2025-12-17 15:25:10 +08:00
update go
This commit is contained in:
337
_posts/go/tour_go/02基础语法/包-变量-函数.md
Normal file
337
_posts/go/tour_go/02基础语法/包-变量-函数.md
Normal file
@@ -0,0 +1,337 @@
|
||||
对于一般的语言使用者来说 ,20% 的语言特性就能够满足 80% 的使用需求,剩下在使用中掌握。
|
||||
|
||||
基于这一理论,Go 基础系列的文章不会刻意追求面面俱到,但该有知识点都会覆盖,目的是带你快跑赶上 Golang 这趟新车。
|
||||
|
||||
**Hurry up , Let's go !**
|
||||
|
||||
## 一个好消息一个坏消息一个潜规则
|
||||
|
||||
Go 的语法类似 C 语言,你是从 C/C++ 语言过来的话学习成本很低,其他语言过来甚至没有编程基础也没关系,这门语言入门很轻松。
|
||||
|
||||
**好消息**是你的键盘得救了,在 Go 的世界里不用在每个语句后面加分号了,C 和C++ 程序员听了喜大普奔,键盘不那么容易磨损了。
|
||||
|
||||
**坏消息**带给习惯花括号换行的朋友,在 Go 中第一个花括号 `{` 不能换行写,必须写在同一行,否则编译不过!
|
||||
|
||||
**潜规则**是任何在 Go 中定义的变量必须使用,如果定义了变量不使用,编译不过!
|
||||
|
||||
怎么样?是不是感觉到满满的霸道总裁味道?
|
||||
|
||||
其实约束多了,程序员自由发挥的空间变少,出错的概率也会大大降低,Google 的大佬们怕你犯错,操碎了心。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## 包
|
||||
|
||||
### 概念
|
||||
|
||||
Go 语言程序都由包构成,类似其他语言中的模块概念,主程序都从 main 包开始运行。
|
||||
|
||||
所以一个程序开头是下面的语句:
|
||||
|
||||
```go
|
||||
package main
|
||||
```
|
||||
|
||||
在程序中也可以导入其他包,这样就可以使用其他包定义的函数或变量。
|
||||
|
||||
### 导入
|
||||
|
||||
导入包语法有多种姿势。
|
||||
|
||||
#### 导入姿势一:单独导入
|
||||
|
||||
```go
|
||||
import os // 导入 os 包
|
||||
import fmt /* 导入 fmt 包*/
|
||||
```
|
||||
|
||||
**fmt 包**:包内有格式化 IO 函数,类似 C 中的 `stdio.h` 和 C++ 中的 `iostream` ,初学者必备,导它!
|
||||
|
||||
**os 包** :中实现了一些 操作系统函数,不依赖平台的接口
|
||||
|
||||
**另外,关于注释,如你所见,完全就是 C 语言里的注释形式,**`//` 或 `/**/ ` 都是允许的。
|
||||
|
||||
#### 导入姿势二:分组导入
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
```
|
||||
|
||||
可以把需要的包,用括号放在一起导入。
|
||||
|
||||
#### 导入姿势三:指定别名导入
|
||||
|
||||
可以在导入的时候指定导入包的别名,这样在调用包函数的时候,可以直接使用包别名。
|
||||
|
||||
```go
|
||||
import f "fmt" // 用别名f 代替 fmt
|
||||
f.Println("go go go") // 用 f 代替了 fmt 调用 Println 函数
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 包导出名称约定
|
||||
|
||||
包中定义的函数或变量,如果是大写字母开头,那么它就是可以导出的,外部使用包的用户可以访问到,类似 C++ 中的 `public` 标识。相反,小写字母开头的名字外部无法使用,使用会报错。
|
||||
|
||||
```go
|
||||
// 如下,Println 和 Getenv 都是大写的名字
|
||||
fmt.Println(os.Getenv("GOPATH"))
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 基本类型
|
||||
|
||||
#### 内置类型
|
||||
|
||||
Go 语言内建的数据类型有下面这些,其实基本上看类型名字,就差不多能知道是什么类型了。
|
||||
|
||||
```go
|
||||
int int8 int16 int32 int64
|
||||
uint uint8 uint16 uint32 uint64 uintptr
|
||||
float32 float64 complex128 complex64
|
||||
bool byte rune string error
|
||||
```
|
||||
|
||||
平常用的最多的类型:
|
||||
|
||||
`int` 代表整型,在 32 位系统上通常为 32 位,在 64 位系统上则为 64 位。
|
||||
|
||||
`string` 字符串类型
|
||||
|
||||
`bool` 布尔类型,分 `true` 和 `false` 两种值。
|
||||
|
||||
|
||||
|
||||
#### 创建类型
|
||||
|
||||
下面的语法创建一个新的类型,类似C++中的typedef语法。
|
||||
|
||||
`type 新类型名字 底层类型`
|
||||
|
||||
```go
|
||||
type ProgramType string // 定义新类型 ProgramType
|
||||
var t1 ProgramType = "Golang"
|
||||
var t2 ProgramType = "C++"
|
||||
```
|
||||
|
||||
不过Go中创建的新类型即使底层类型是一致的也不能相互操作,**这样起到很好的类型隔离作用**。
|
||||
|
||||
比如下面的代码,虽然`ProgramType` 和 `CompanyType` 都是` string` 类型,但是不能相互操作,下面举例说明:
|
||||
|
||||
```go
|
||||
type ProgramType string // 定义新类型 ProgramType
|
||||
type CompanyType string // 定义新类型 ProgramType
|
||||
var t2, t2 ProgramType = "Golang", "C++"
|
||||
var c1, c2 CompanyType = "Google", "Tencent"
|
||||
fmt.Println(t1+t2) // 同类型相加合法
|
||||
fmt.Println(t1+c1) // 不同类型相加非法
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 类型转换
|
||||
|
||||
不像 C 中有隐式类型转换,**在 Go 中 不同类型的项之间赋值时需要显式转换,否则编译会报错**!语法上,相对于 C 语言的强制转换语法换了下括号的位置,Go 语法如下。
|
||||
|
||||
```
|
||||
T(v) // 把值 v 转换为类型 T
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
```go
|
||||
var varint int = 66
|
||||
var varf float32 = float32(varint) // int 转换 float32
|
||||
fmt.Printf("%T %v %T %v \n", varint, varint, varf, varf) // %T输出值的类型 %v输出值
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 变量
|
||||
|
||||
### 声明
|
||||
|
||||
Go 里面的变量声明其实和 C 语言差不多,唯一的区别是把变量类型放在在变量名字后面,另外多了一个 `var` 关键字标识。
|
||||
|
||||
```go
|
||||
var imVar int // 声明了一个 int 类型的 imVar 变量
|
||||
```
|
||||
|
||||
当然也可以多个同类型变量一起声明
|
||||
|
||||
```go
|
||||
var imVar1, imVar2, imVar3 int // 一口气声明了三个 int 类型的变量
|
||||
```
|
||||
|
||||
或者,多个不同类型的变量声明分组一起声明
|
||||
|
||||
```go
|
||||
var (
|
||||
i int
|
||||
b bool
|
||||
s string
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 初始化
|
||||
|
||||
#### 未初始化
|
||||
|
||||
未初始化的对象会被赋予**零值**,也就是默认值。
|
||||
|
||||
- 数值类型初始值 `0`
|
||||
- 布尔类型初始值 `false`
|
||||
- 字符串为初始值 `""`(空字符串)
|
||||
|
||||
|
||||
|
||||
#### 普通初始化
|
||||
|
||||
可以声明之后单个初始化
|
||||
|
||||
```go
|
||||
var imVar int
|
||||
imVar = 6
|
||||
```
|
||||
|
||||
也可以声明和初始化一步到位
|
||||
|
||||
```go
|
||||
var imVar0 int = 7
|
||||
```
|
||||
|
||||
还可以批量声明加初始化一步到位
|
||||
|
||||
```go
|
||||
var imVar4, imVar5 int = 4, 5
|
||||
```
|
||||
|
||||
多个不同类型的变量声明和初始化可以分组同时进行,像下面这样。
|
||||
|
||||
```go
|
||||
var (
|
||||
i int = 1
|
||||
b bool = false
|
||||
s string = "golang"
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 偷懒初始化
|
||||
|
||||
##### 类型自动推导
|
||||
|
||||
如果初始化式右边的值是已存在确定类型的值,可以偷懒省略变量类型,聪明的 Go 会自动推导类型。
|
||||
|
||||
```go
|
||||
var imVar4, imVar5 = 4, 5 // 省略了左边的 int 类型,自动推导imVar4, imVar5是int类型
|
||||
```
|
||||
|
||||
####
|
||||
|
||||
##### 简短初始化
|
||||
|
||||
**在函数内部**,可以使用简短赋值语句` := `来代替 `var` 关键字**声明并初始化**变量。
|
||||
|
||||
```go
|
||||
imVar6, imVar7 := 8, 9 // 声明并初始化了 imVar6, imVar7
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 常量
|
||||
|
||||
常量用 `const` 关键字声明,并且声明之后必须紧接着赋值,常量可以是字符、字符串、布尔值或数值 ,注意:**常量不能用 `:=` 语法声明** 。
|
||||
|
||||
```go
|
||||
const imCnt int = 1 // 带类型的常量定义
|
||||
const imCnt1 = 1 // 省略类型的常量定义,自动推导类型
|
||||
```
|
||||
|
||||
Go 语言内建下面几种常量
|
||||
|
||||
```go
|
||||
true false iota nil // 内建常量
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 函数
|
||||
|
||||
### 声明
|
||||
|
||||
函数用关键字 `func` 来声明,带参数列表,把返回值类型放在最后,下面定义了一个简单的乘法函数,带两个整型参数,返回值也是整型。
|
||||
|
||||
```go
|
||||
func mult(i int, j int) int {
|
||||
return i * j
|
||||
}
|
||||
```
|
||||
|
||||
当函数参数类型相同时,可以只写最后一个参数的类型,下面这样简写也是可以的。
|
||||
|
||||
```go
|
||||
func mult(i, j int) int {
|
||||
return i * j
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 返回值
|
||||
|
||||
#### 多返回值
|
||||
|
||||
函数返回值可以是一个,也可以是多个,下面的函数就返回了 `i` 的平凡和 `j` 的平方两个返回值。
|
||||
|
||||
```go
|
||||
func more(i, j int) (int, int) {
|
||||
return i * i, j * j
|
||||
}
|
||||
```
|
||||
|
||||
#### 返回值命名
|
||||
|
||||
前面例子只指定了返回值类型,可以指定返回值名称,这样更加便于理解,同时,指定的名称可在函数内使用。
|
||||
|
||||
```go
|
||||
func retName(i, j int) (x, y int) {
|
||||
x = i * i
|
||||
y = j * j
|
||||
return x, y // 可用 return 代替,表示返回所有已命名的返回值。
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
通过本文的学习,我们掌握了 Golang 中的几个基础概念和用法:包、基本数据类型、变量、常量、函数。这些语法基础是Golang 的下层建筑,万丈高楼平地起,本节为后续学习打下了基础。
|
||||
|
||||
感谢各位的阅读,文章的目的是分享对知识的理解,技术类文章我都会反复求证以求最大程度保证准确性,若文中出现明显纰漏也欢迎指出,我们一起在探讨中学习.
|
||||
|
||||
今天的技术分享就到这里,我们下期再见。
|
||||
|
||||
-----
|
||||
|
||||
|
||||
|
||||
**原创不易,不想被白票,如果在我这有收获,就动动手指点个「在看」或给个「转发」是对我持续创作的最大支持。**
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user