Golang基础语法

Golang基础语法
墨颜丶Go 语言结构
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
接下来让我们来看下简单的代码,该代码输出了"Hello World!":
实例
1 | package main |
让我们来看下以上程序的各个部分:
- 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
- 下一行
import "fmt"
告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。 - 下一行
func main()
是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。 - 下一行
/* */
是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。 - 下一行
fmt.Println(...)
可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
使用fmt.Print("hello, world\n")
可以得到相同的结果。
Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。 - 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
执行 Go 程序
让我们来看下如何编写 Go 代码并执行它。步骤如下:
打开编辑器如
Vscode
,将以上代码添加到编辑器中。将以上代码保存为
hello.go
打开命令行,并进入程序文件保存的目录中。
输入命令
go run hello.go
并按回车执行代码。如果操作正确你将在屏幕上看到 “Hello World!” 字样的输出。
1
2go run hello.go
Hello, World!我们还可以使用 go build 命令来生成二进制文件:
1
2
3
4
5go build hello.go
ls
hello hello.go
./hello
Hello, World!
注意
需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误:
1 | package main |
Go 包管理
关于包管理的总结:
- 一个文件夹可以称为一个包。
- 在文件夹(包)中可以创建多个文件。
- 在同一个包下的每个为文件中必须指定
包名称且相同
重点:关于包的分类
- main包,如果是main包,则必须写一个main函数,此函数就是项目的入口(main主函数)。 编译生成的就是一个可执行文件。
- 非main包,用来将代码进行分类,分别放在不同的包和文件中。
注意:
调用其他包的功能,需要先 import 导入,然后再使用;调用自己包中的功能时,直接调用即可(无需导入)
文件中的函数首字母是小写,表示此函数只能被当前包内部文件调用。首字母是大写,则意味着任何包都可以调用。
Go 基础语法
输出
在终端将想要展示的数据显示出来,例如:欢迎登录、请输入用户名等。。。
- 内置函数
- println
- fmt包(推荐)
- fmt.Print
- fmt.Println
扩展:fmt.Print
和print
函数的区别在于fmt.Print
可以进行格式化输出,可以根据需要进行格式化指示符的处理,而print
函数则直接输出传入的参数值。另外,fmt.Print
和print
函数都需要通过"fmt"
包来引入。
fmt.Print
有几个变种:
Print: 输出到控制台,不接受任何格式化操作
Println: 输出到控制台并换行
Printf : 只可以打印出格式化的字符串,只可以直接输出字符串类型的变量(不可以输出别的类型)
Sprintf:格式化并返回一个字符串而不带任何输出
Print 和 Println
1 | name := "jerry" |
格式化输出 Printf
占位符 |
---|
%v :以默认的方式打印变量的值 |
%#v :相应值的Go语法表示 |
%T :打印对应值的类型 |
%+d :带符号的整型,%d 不带符号的整型 |
%o :不带零的八进制,%#o 带零的八进制 |
%x :小写的十六进制,%X 大写的十六进制,%#x 带0x的十六进制 |
%b :打印整型的二进制 |
%t :打印true 或 false |
%s :输出字符串表示,%-5s 最小宽度为5(左对齐) |
%f 小数点而无指数,默认精度为6 |
%e 科学计数法,如-1234.456e+78 |
%p 带0x的指针,%#p 不带0x的指针 |
1 | name := "jerry" |
Sprintf
Printf和Sprintf都是替换字符串,Printf是直接输出到终端,Sprintf是不直接输出到终端,而是返回该字符串
1 | name := "jerry" |
总结
1 | package main |
注释
注释只是为了提高可读性,不会被计算机编译。
- 单行注释:
// 注释内容
- 多行注释:
/* 注释内容 */
快捷:contrl + ?
行分隔符
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用;
人为区分,但在实际开发中我们并不鼓励这种做法。
Go 变量
在计算机编程中,我们用变量来保存并管理很多数据,并用变量名来区分、识别和处理这些数据。
变量本质上是一种对内存地址的引用,让你能够把程序中准备使用的每一段数据都赋给一个简短、易于记忆的名字进行操作。
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字:
1 | var identifier type // var 变量名 变量类型 |
可以一次声明多个变量:
1 | var identifier1, identifier2 type |
声明 + 赋值
1
2
3
4
5
6
7
8var name string = "jerry"
fmt.Println(name)
var age int = 11
fmt.Println(age)
var flag bool = true
fmt.Println(flag)先声明后赋值
1
2
3
4
5// 声明了一个字符类型变量 name
var name string
// 给name变量赋值
name = "jerry"
fmt.Println(name)声明并赋值
1
2
3
4var age = 11
fmt.Println(age)
var height = 189.999
fmt.Printf("%.0f米", height) // 190米声明多个变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
// 这种因式分解关键字的写法一般用于声明全局变量
var (
a int = 3 // 默认值 0
b string = "go" // 默认值“” 空
c bool = true // 默认值 false
)
fmt.Println(a, b, c)
声明变量的意义?
编写代码省事
1
2
3
4
5// 文本,请将文本输出3次:"伤情最是晚凉天,憔悴斯人不堪怜。"
var message string = "伤情最是晚凉天,憔悴斯人不堪怜。"
fmt.Println(message)
fmt.Println(message)
fmt.Println(message)存储结果,方便之后使用
1
2
3
4
5
6
7// 存储结果,方便之后使用
var v1 int = 99
var v2 int = 33
var v3 int = v1 + v2
var v4 int = v1 * v2
var v5 int = v1 + v2 + v3 + v4
fmt.Println(v1, v2, v3, v4, v5)存储用户输入的值
1
2
3
4
5
6
7var name string
fmt.Scanf("%s", &name) // 用户输入字符串并赋值给name变量
if name == "jerry" {
fmt.Println("用户名输入正确")
} else {
fmt.Println("用户名输入失败")
}
变量名要求
【要求】变量名必须只包含:字母、数字、下划线
1
2var %1 string,错误
var $ string,错误【要求】数字不能开头
1
2
3var 1 string 错误
var 1name string 错误
var _ string 正确【要求】不能使用go语言内置的关键字
1
var var string = "南通州北通州南北通州通南北" 错误
1
break、default、func、interface、select、case、defer、go、map、struct、chan、else、goto、package、switch、const、fallthrough、if、range、type、continue、for、import、return、var
建议
- 变量名见名知意:name/age/num ; v1、v2、v3
- 驼峰式命名:myBossName / startDate
练习题:
1 | var n1 int |
变量简写
声明+赋值
1
2
3
4
5var name string = "jerry"
var name = "jerry"
name := "jerry" // 推荐先声明再赋值
1
2
3
4
5
6
7
8var name string
var message string
var data string
var name,message,data string
name = "jerry"
message = "中奖了"
data = "中了5000w"
因式分解,例如:声明5个变量,分别有字符串、整型
1 | var ( |
扩展:go编译器会认为声明变量不使用 就是耍流氓。
匿名变量
匿名变量即没有命名的变量,在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_
表示。
1 | a,b,c :=4,5,6 |
匿名变量不占用命名空间,不会分配内存
让代码非常清晰,基本上屏蔽掉了可能混淆代码阅读者视线的内容,从而大幅降低沟通的复杂度和代码维护的难度。
作用域
如果我们定义了大括号,那么在大括号中定义的变量。
- 不能被上级使用。
- 可以在同级使用。
- 可以再子级使用。
1 | package main |
全局变量和局部变量
- 全局变量,未写在函数中的变量称为全局变量;不可以使用
v1:=xx
方式进行简化;可以基于因式分解方式声明多个变量,应该使用var
关键字;项目中寻找变量时最后一环。 - 局部变量,编写在{}里面的变量;可以使用任意方式简化;可以基于因式分解方式声明多个变量;
1 | package main |
赋值及内存相关
示例1:
1 | name := "jerry" |
示例2:
1 | name := "jerry" |
注意:这一点与python不同。
1 | package main |
示例3:
1 | name := "jerry" |
1 | package main |
简短形式,使用 := 赋值操作符
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。
a 和 b 的类型(int 和 bool)将由编译器自动推断。
这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。
注意事项
- 如果变量已经使用 var 声明过了,再使用 *:=* 声明变量,就产生编译错误,格式:
1 | v_name := value |
例如:
1 | var intVal int |
直接使用下面的语句即可:
1 | intVal := 1 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句 |
intVal := 1 相等于:
1 | var intVal int |
如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。
如果你在定义变量 a 之前使用它,则会得到编译错误 undefined: a。
如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:
1 | package main |
尝试编译这段代码将得到错误 a declared but not used。
此外,单纯地给 a 赋值也是不够的,这个值必须被使用,所以使用
1 | fmt.Println("hello, world", a) |
会移除错误。
但是全局变量是允许声明但不使用的。 同一类型的多个变量可以声明在同一行,如:
1 | var a, b, c int |
多变量可以在同一行进行赋值,如:
1 | var a, b int |
上面这行假设了变量 a,b 和 c 都已经被声明,否则的话应该这样使用:
1 | a, b, c := 5, 7, "abc" |
右边的这些值以相同的顺序赋值给左边的变量,所以 a 的值是 5, b 的值是 7,c 的值是 “abc”。
这被称为 并行 或 同时 赋值。
如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a,两个变量的类型必须是相同。
空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。
_ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
并行赋值也被用于当一个函数返回多个返回值时,比如这里的 val 和错误 err 是通过调用 Func1 函数同时得到:val, err = Func1(var1)。
局部变量:在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
全局变量:在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
备注:
1.局部变量不会一直存在,在函数被调用时存在,函数调用结束后变量就会被销毁,即生命周期。
2.Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
阶段练习题
package main
的作用?单行注释和多行注释分别是什么?
下面声明变量的方式错误的有哪些?
1
2
3
4
5var name = "jerry"
var age int = 18
hobby = "嫂子"
nickName string = "一米八大高个"
webSite := "秃头统治地球"1
2var age int = 18
age = 19下面声明变量的方式正确的有哪些?
1
2
3
4
5
6
7
8var v1,v2,v3 int
var (
v6 = 123
v7 string
)
var v4,v5 = 11,22
v4,v5 = 11,22
v4,v5 := 11,22变量名规范。
看代码写结果
1
2
3
4
5
6
7
8
9
10package main
import "fmt"
var number = 9999
func main() {
number := 666
fmt.Println(number)
}看代码写结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14package main
import "fmt"
var number = 99
func main() {
number := 66
if true {
number := 33
fmt.Println(number)
}
fmt.Println(number)
}看代码写结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import "fmt"
var number = 99
func main() {
number := 66
if true {
number := 33
fmt.Println(number)
}
number = 88
fmt.Println(number)
}看代码写结果
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "fmt"
var number = 99
func main() {
if true {
fmt.Println(number)
}
number = 88
fmt.Println(number)
}看代码写结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import "fmt"
var number = 99
func main() {
number := 88
if true {
number = 123
fmt.Println(number)
}
fmt.Println(number)
}看代码写结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import "fmt"
var number = 99
func main() {
fmt.Println(number)
number := 88
if true {
number = 123
fmt.Println(number)
}
fmt.Println(number)
}
Go 数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。
Go 语言按类别有以下几种数据类型:
序号 | 类型和描述 |
---|---|
1 | 布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。 |
2 | 数字类型 整型 int 和浮点型 float32 精度约为7位小数、float64精度约为15位小数,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。 |
3 | 字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。 |
4 | 派生类型: 包括:(a) 指针类型(Pointer)(b) 数组类型© 结构化类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型(interface)(h) Map 类型 |
1 | package main |
整形
字节了解:
字节(Byte):计算机中数据储存的单位。
位(bit):也叫作“比特”,计算机中数据储存的最小单位,因为在计算机中是以二进制的形式数据储存,所以每个位以“0”或“1”表示。
位和字节的关系是:8个位组成一个字节。
字节与位的关系:1Byte=8bit。
- 整形类型
具体类型 | 取值范围 |
---|---|
int8 | -128到127 |
uint8 | 0到255 |
int16 | -32768到32767 |
uint16 | 0到65535 |
int32 | -2147483648到2147483647 |
uint32 | 0到4294967295 |
int64 | -9223372036854775808到9223372036854775807 |
uint64 | 0到18446744073709551615 |
uint | 与平台相关,32位操作系统上就是uint32 ,64位操作系统上就是uint64 |
int | 与平台相关,32位操作系统上就是int32 ,64位操作系统上就是int64 |
1 | var x int |
- 进制转换
1 | // 十进制转化 |
浮点型
float类型分为float32
和float64
两种类型,这两种浮点型数据格式遵循 IEEE 754 标准。
单精度浮点数占用4个字节(32位)存储空间来存储一个浮点数。而双精度浮点数使用 8个字节(64位)存储空间来存储一个浮点数。
单精度浮点数最多有7位十进制有效数字,如果某个数的有效数字位数超过7位,当把它定义为单精度变量时,超出的部分会自动四舍五入。双精度浮点数可以表示十进制的15位有效数字,超出的部分也会自动四舍五入。
浮点类型默认声明为float64。
1 | var f1 float32 // float32: 单精度浮点型 |
科学计数表示
1 | var f1 = 2e10 // 即使是整数用科学技术表示也是浮点型 |
布尔类型
布尔类型是最基本数据类型之一,只有两个值:true和false,分别代表逻辑判断中的真和假,主要应用在条件判断中。
1 | package main |
字符串
字符串是最基本也是最常用的数据类型,是通过双引号将多个字符按串联起来的一种数据,用于展示文本。
1 | var s = "hello yuan" |
单引号只能标识字符
字符串的基本操作
字符串在内存中是一段连续存储空间
注意:
- 索引从零开始计数
- go语言不支持负索引
1 | var s = "hello yuan" |
转义符
Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。
转义符 | 含义 |
---|---|
\r | 回车符(返回行首) |
\n | 换行符(直接跳到下一行的同列位置) |
\t | 制表符 |
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
举个例子,我们要打印一个Windows平台下的一个文件路径:
1 | package main |
多行字符串
Go语言中要定义一个多行字符串时,就必须使用反引号
字符:
1 | s1 := `第一行 |
反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。
字符串的常用方法
方法 | 介绍 |
---|---|
len(str) | 求长度 |
strings.ToUpper ,strings.ToLower | 生成一个新的全部大写的字符串,生成一个新的全部小写的字符串 |
strings.ReplaceAll | 生成一个新的原字符串被指定替换后的字符串 |
strings.Contains | 判断是否包含 |
strings.HasPrefix,strings.HasSuffix | 前缀/后缀判断 |
strings.Trim | 去除字符串两端匹配的内容 |
strings.Index(),strings.LastIndex() | 子串出现的位置 |
strings.Split | 分割,将字符串按指定的内容分割成数组 |
strings.Join(a[]string, sep string) | join操作,将数组按指定的内容拼接成字符串 |
1 | package main |
Go 常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。在Python、Java编程规范中,常量⼀般都是全⼤写字母,但是在Golang中,⼤⼩写是具有⼀定特殊含义的,所以不⼀定所有常量都得全⼤写。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式:
1 | const 常量名[数据类型] = value |
数据类型可以忽略不写,Golang编译器会⾃动推断出数据类型。 在使⽤时,要注意以下⼏点:
- 数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
- 满⾜多重赋值
- 常量只定义不使⽤,编译不会报错
- 常量可以作为枚举,常量组
- 常量组中如不指定类型和初始化值,则与上⼀⾏⾮空常量右值相同
- 显⽰指定类型的时候,必须确保常量左右值类型⼀致,需要时可做显⽰类型转换。
多个相同类型的声明可以简写为:
1 | const c_name1, c_name2 = value1, value2 |
常量的应用:
1 | package main |
以上实例运行结果为:
1 | 面积为 : 50 |
常量还可以用作枚举:
1 | const ( |
因式分解
1 | package main |
全局
1 | package main |
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota 可以被用作枚举值:
1 | const ( |
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:
1 | const ( |
用法
1 | package main |
更有趣的iota实例
1 | package main |
1 | package main |
iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。
简单表述:
- i=1:左移 0 位,不变仍为 1。
- j=3:左移 1 位,变为二进制 110,即 6。
- k=3:左移 2 位,变为二进制 1100,即 12。
- l=3:左移 3 位,变为二进制 11000,即 24。
注:<<n==*(2^n)。
Go 运算符
运算符用于在程序运行时执行数学或逻辑运算。
Go 语言内置的运算符有:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符
算术运算符
下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
– | 自减 | A-- 输出结果 9 |
1 | package main |
关系运算符
下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
1 | package main |
逻辑运算符
下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
ll | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A ll B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A && B) 为 True |
以下实例演示了逻辑运算符的用法:
1 | package main |
位运算符
位运算符对整数在内存中的二进制位进行操作。
下表列出了位运算符 &, |, 和 ^ 的计算:
p | q | p & q | p l q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假定 A = 60; B = 13; 其二进制数转换为:
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
Go 语言支持的位运算符如下表所示。假定 A 为60,B 为13:
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
l | 按位或运算符"l"是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | (A l B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | (A ^ B) 结果为 49, 二进制为 0011 0001 |
<< | 左移运算符"<<“是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移运算符">>“是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
以下实例演示了位运算符的用法:
1 | package main |
必知必会概念:
位运算指的是二进制之间的运算:
计算机中的 存储、运算、网络传输等任何的行为,本质上都是二进制的操作。例如:01010101。
1
2A B
hello -> 0101010010101 -> hello信息表现形式
1
2二进制表示:0101010010101 -> hello
十进制表示:1921 -> hello十进制和二进制的转换关系
十进制 二进制 0 0 1 1 2 10 3 11 4 100 5 101 6 110 7 111 8 1000 9 1001 10 1010 … … 二进制转换为十进制
1
210101 -> 2**4 + 2**2 + 2**0 => 16 + 4 + 1 => 21
101010010101 -> 2**11 + 2**9 + ....十进制转换成二进制
1
99 -> 64 + 32 + 2 + 1 -> 2**6 + 2**5 + 2**1 + 2*0 -> 1100011
赋值运算符
下表列出了所有Go语言的赋值运算符。
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A + B 将 A + B 表达式结果赋值给 C |
+= | 相加后再赋值 | C += A 等于 C = C + A |
-= | 相减后再赋值 | C -= A 等于 C = C - A |
*= | 相乘后再赋值 | C *= A 等于 C = C * A |
/= | 相除后再赋值 | C /= A 等于 C = C / A |
%= | 求余后再赋值 | C %= A 等于 C = C % A |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2 |
以下实例演示了赋值运算符的用法:
1 | 第 1 行 - = 运算符实例,c 值为 = 21 |
其他运算符
下表列出了Go语言的其他运算符。
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
以下实例演示了其他运算符的用法:
1 | package main |
运算符优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + - | ^ |
3 | == != < <= > >= |
2 | && |
1 | || |
当然,你可以通过使用括号来临时提升某个表达式的整体运算优先级。
1 | package main |
Go 输入
go语言fmt包下有三个函数,可以在程序运行过程中从标准输入获取用户的输入:
- fmt.Scan: 这个函数用于读取输入,直到遇到空白字符(如空格、制表符、换行符等)
- fmt.Scanln:这个函数类似于
fmt.Scan
,但它会一直读取直到遇到换行符 - fmt.Scanf:这个函数类似于
fmt.Scan
,但它会一直读取直到遇到换行符
fmt.Scan
语法:
1 | func Scan(a ...interface{}) (n int, err error) |
- Scan 从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符。
- 本函数返回成功扫描的数据个数和遇到的任何错误。如果读取的数据个数比提供的参数少,会返回一个错误报告原因。
1 | package main |
fmt.Scanln
语法
1 | func Scanln(a ...interface{}) (n int, err error) |
- Scanln类似于Scan,它遇到换行立即停止扫描。
- 本函数返回成功扫描的数据个数和遇到的任何错误。
Scanln和Scan的区别就是Scanln遇到换行立即结束输入,而Scan则会将换行符作为一个空白符继续下一个输入
1 | package main |
fmt.Scanf
语法
1 | func Scanf(format string, a ...interface{})(n int, err error) |
- Scanf从标准输入扫描文本,根据format参数指定的格式去读取由空白符分隔的值保存到传递给本函数的参数中。
- 本函数返回成功扫描的数据个数和遇到的任何错误。
1 | // 案例1 |
Go 知识点总结
fmt.Print
函数用于将格式化的字符串输出到标准输出(通常是终端)。它的语法如下:
1 | fmt.Println("Hello, World!") // 输出: Hello, World! |
fmt.Printf()
: 用于按照指定的格式将参数格式化为字符串并打印到标准输出。
1 | name := "Alice" |
fmt.Scanf()
: 用于从标准输入读取数据并根据指定的格式进行解析。
1 | var name string |
fmt.Fprintf()
: 用于将格式化的数据写入到指定的io.Writer
中。
1 | file, _ := os.Create("output.txt") // 创建一个文件用于写入 |