Golang基础语法

Go 语言结构

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释

接下来让我们来看下简单的代码,该代码输出了"Hello World!":

实例

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
}

让我们来看下以上程序的各个部分:

  1. 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
  2. 下一行import "fmt"告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
  3. 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
  4. 下一行/* */是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
  5. 下一行fmt.Println(...)可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
    使用fmt.Print("hello, world\n")可以得到相同的结果。
    Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。
  6. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

执行 Go 程序

让我们来看下如何编写 Go 代码并执行它。步骤如下:

  1. 打开编辑器如Vscode,将以上代码添加到编辑器中。

  2. 将以上代码保存为 hello.go

  3. 打开命令行,并进入程序文件保存的目录中。

  4. 输入命令go run hello.go 并按回车执行代码。

  5. 如果操作正确你将在屏幕上看到 “Hello World!” 字样的输出。

    1
    2
    $ go run hello.go
    Hello, World!
  6. 我们还可以使用 go build 命令来生成二进制文件:

    1
    2
    3
    4
    5
    $ go build hello.go 
    $ ls
    hello hello.go
    $ ./hello
    Hello, World!

注意

需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误:

1
2
3
4
5
6
7
8
package main

import "fmt"

func main()  
{  // 错误,{ 不能在单独的行上
    fmt.Println("Hello, World!")
}

Go 包管理

关于包管理的总结:

  • 一个文件夹可以称为一个包。
  • 在文件夹(包)中可以创建多个文件。
  • 在同一个包下的每个为文件中必须指定 包名称且相同

重点:关于包的分类

  • main包,如果是main包,则必须写一个main函数,此函数就是项目的入口(main主函数)。 编译生成的就是一个可执行文件。
  • 非main包,用来将代码进行分类,分别放在不同的包和文件中。

image-20230922175010330

注意:

  • 调用其他包的功能,需要先 import 导入,然后再使用;调用自己包中的功能时,直接调用即可(无需导入)

  • 文件中的函数首字母是小写,表示此函数只能被当前包内部文件调用。首字母是大写,则意味着任何包都可以调用。

Go 基础语法

输出

在终端将想要展示的数据显示出来,例如:欢迎登录、请输入用户名等。。。

  • 内置函数
    • print
    • println
  • fmt包(推荐)
    • fmt.Print
    • fmt.Println

扩展:fmt.Printprint函数的区别在于fmt.Print可以进行格式化输出,可以根据需要进行格式化指示符的处理,而print函数则直接输出传入的参数值。另外,fmt.Printprint函数都需要通过"fmt"包来引入。

fmt.Print有几个变种:

Print: 输出到控制台,不接受任何格式化操作

Println: 输出到控制台并换行

Printf : 只可以打印出格式化的字符串,只可以直接输出字符串类型的变量(不可以输出别的类型)

Sprintf:格式化并返回一个字符串而不带任何输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	name := "jerry"
age := 11
fmt.Print(name, age, "无换行与下一行粘连")
fmt.Println("hello world")
fmt.Println(name)
fmt.Println(age)
fmt.Println(name, age)
fmt.Println("姓名:", name, "年龄:", age)

//jerry11无换行与下一行粘连hello world
//jerry
//11
//jerry 11
//姓名: jerry 年龄: 11

格式化输出 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
	name := "jerry"
age := 11
isMarried := false
salary := 9999.88888
fmt.Printf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
fmt.Printf("姓名:%v 年龄:%v 婚否:%v 薪资:%v\n", name, age, isMarried, salary)
fmt.Printf("姓名:%#v 年龄:%#v 婚否:%#v 薪资:%#v\n", name, age, isMarried, salary)

//姓名:jerry 年龄:11 婚否:false 薪资:9999.89
//姓名:jerry 年龄:11 婚否:false 薪资:9999.88888
//姓名:"jerry" 年龄:11 婚否:false 薪资:9999.88888


// 整形和浮点型
fmt.Printf("%b\n", 12) // 二进制表示:1100
fmt.Printf("%d\n", 12) // 十进制表示:12
fmt.Printf("%o\n", 12) // 八进制表示:14
fmt.Printf("%x\n", 12) // 十六进制表示:c
fmt.Printf("%X\n", 12) // 十六进制表示:c
fmt.Printf("%f\n", 3.1415) // 有小数点而无指数:3.141500
fmt.Printf("%.3f\n", 3.1415) // 3.142
fmt.Printf("%e\n", 1000.25) // 科学计数法: 1.000250e+03,默认精度为6

// 设置宽度
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1001", "alvin", 100)
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1002", "zuibangdeyuanlaoshi", 98)
fmt.Printf("学号:%s 姓名:%-20s 平均成绩:%-4d\n", "1003", "x", 78)

//1100
//12
//14
//c
//C
//3.141500
//3.142
//1.000250e+03
//学号:1001 姓名:alvin 平均成绩:100
//学号:1002 姓名:zuibangdeyuanlaoshi 平均成绩:98
//学号:1003 姓名:x 平均成绩:78

Sprintf

Printf和Sprintf都是替换字符串,Printf是直接输出到终端,Sprintf是不直接输出到终端,而是返回该字符串

1
2
3
4
5
6
name := "jerry"
age := 11
isMarried := false
salary := 9999.88888
info := fmt.Sprintf("姓名:%s 年龄:%d 婚否:%t 薪资:%.2f\n", name, age, isMarried, salary)
fmt.Println(info)

总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
// 基于内置函数(不推荐)
//print("好吃不过饺子 \n")
//print("好玩不过嫂子 \n")
//println("好吃不过饺子")
//println("好玩不过嫂子")

// fmt包(推荐)
//fmt.Print("好吃不过饺子 \n")
//fmt.Print("好玩不过嫂子 \n")
//fmt.Println("好玩不过嫂子")
//fmt.Println("好玩不过嫂子")

// fmt包 扩展:格式化输出
// %s,占位符 "文本"
// %d,占位符 整数
// %f,占位符 小数(浮点数)
// %.2f,占位符 小数(保留小数点后2位,四舍五入)
// 百分比
fmt.Printf("老baby开着%s去接%s,多少钱一次?%d块。嫂子给打折吧,%.2f怎么样?小哥哥包你100%%满意", "大奔", "客", 100, 3.889)
// 老baby开着大奔去接客,多少钱一次?100块。嫂子给打折吧,3.89怎么样?小哥哥包你100%满意
}

注释

注释只是为了提高可读性,不会被计算机编译。

  • 单行注释: // 注释内容
  • 多行注释: /* 注释内容 */

快捷:contrl + ?

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

如果你打算将多个语句写在同一行,它们则必须使用;人为区分,但在实际开发中我们并不鼓励这种做法。

Go 变量

在计算机编程中,我们用变量来保存并管理很多数据,并用变量名来区分、识别和处理这些数据。

变量本质上是一种对内存地址的引用,让你能够把程序中准备使用的每一段数据都赋给一个简短、易于记忆的名字进行操作。

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。

声明变量的一般形式是使用 var 关键字:

1
var identifier type   // var  变量名 变量类型

可以一次声明多个变量:

1
var identifier1, identifier2 type
  • 声明 + 赋值

    1
    2
    3
    4
    5
    6
    7
    8
    var 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
    4
    var 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
    7
    var name string
    fmt.Scanf("%s", &name) // 用户输入字符串并赋值给name变量
    if name == "jerry" {
    fmt.Println("用户名输入正确")
    } else {
    fmt.Println("用户名输入失败")
    }

变量名要求

  • 【要求】变量名必须只包含:字母、数字、下划线

    1
    2
    var %1 string,错误
    var $ string,错误
  • 【要求】数字不能开头

    1
    2
    3
    var 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
2
3
var n1 int 
var data bool
var _9 string

变量简写

  • 声明+赋值

    1
    2
    3
    4
    5
    var name string = "jerry"

    var name = "jerry"

    name := "jerry" // 推荐
  • 先声明再赋值

    1
    2
    3
    4
    5
    6
    7
    8
    var name string
    var message string
    var data string

    var name,message,data string
    name = "jerry"
    message = "中奖了"
    data = "中了5000w"

因式分解,例如:声明5个变量,分别有字符串、整型

1
2
3
4
5
6
7
8
9
10
var (
name = "jerry"
age = 18
hobby = "大保健"
salary = 1000000
gender string // 只声明但不赋值,有一个默认: ""
length int // 只声明但不赋值,有一个默认: 0
sb bool // 只声明但不赋值,有一个默认: false
)
fmt.Println(name, age, hobby, salary, gender,length,sb)

扩展:go编译器会认为声明变量不使用 就是耍流氓。

匿名变量

匿名变量即没有命名的变量,在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示。

1
2
3
4
5
a,b,c :=4,5,6
fmt.Println(a,b,c)
// 如果只想接受第个变量,可以对前两个变量匿名
_,_,x := 4,5,6
fmt.Println(x)

匿名变量不占用命名空间,不会分配内存

让代码非常清晰,基本上屏蔽掉了可能混淆代码阅读者视线的内容,从而大幅降低沟通的复杂度和代码维护的难度。

作用域

如果我们定义了大括号,那么在大括号中定义的变量。

  • 不能被上级使用。
  • 可以在同级使用。
  • 可以再子级使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
name := "jerry"
fmt.Println(name)
if true {
age := 18
name := "gooo"
fmt.Println(age)
fmt.Println(name)
}
fmt.Println(name)
}

全局变量和局部变量

  • 全局变量,未写在函数中的变量称为全局变量;不可以使用v1:=xx方式进行简化;可以基于因式分解方式声明多个变量,应该使用 var 关键字;项目中寻找变量时最后一环。
  • 局部变量,编写在{}里面的变量;可以使用任意方式简化;可以基于因式分解方式声明多个变量;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

// 全局变量(不能以省略的方式)
var school string = "大帅帅IT教育" // 可以
//var school = "大帅帅IT教育" // 可以
//school := "大帅帅IT教育" // 不可以

var (
v1 = 123
v2 = "你好"
v3 int
)

func main() {

name := "jerry" // 局部变量
fmt.Println(name)
if true {
age := 18 // 局部变量
name := "gooo" // 局部变量
fmt.Println(age)
fmt.Println(name)
}
fmt.Println(name)
fmt.Println(school)
fmt.Println(v1, v2, v3)
}

赋值及内存相关

示例1:

1
name := "jerry"

image-20230922160451077

示例2:

1
2
name := "jerry"
nickname := name

image-20230922160620118

注意:这一点与python不同。

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
name := "jerry"
nickname := name

fmt.Println(name, &name)
fmt.Println(nickname, &nickname)
}

示例3:

1
2
3
4
name := "jerry"
nickname := name

name = "gooo"

image-20230922160620118

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
name := "jerry"
nickname := name
fmt.Println(name, &name)
fmt.Println(nickname, &nickname)

name = "gooo"
fmt.Println(name, &name)
fmt.Println(nickname, &nickname)
}

简短形式,使用 := 赋值操作符

我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。

a 和 b 的类型(int 和 bool)将由编译器自动推断。

这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。

注意事项

  1. 如果变量已经使用 var 声明过了,再使用 *:=* 声明变量,就产生编译错误,格式:
1
v_name := value

例如:

1
2
var intVal int 
intVal :=1 // 这时候会产生编译错误,因为 intVal 已经声明,不需要重新声明

直接使用下面的语句即可:

1
intVal := 1 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句

intVal := 1 相等于:

1
2
var intVal int 
intVal =1

如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。

如果你在定义变量 a 之前使用它,则会得到编译错误 undefined: a。

如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
var a string = "abc"
fmt.Println("hello, world")
}

尝试编译这段代码将得到错误 a declared but not used

此外,单纯地给 a 赋值也是不够的,这个值必须被使用,所以使用

1
fmt.Println("hello, world", a)

会移除错误。

但是全局变量是允许声明但不使用的。 同一类型的多个变量可以声明在同一行,如:

1
var a, b, c int

多变量可以在同一行进行赋值,如:

1
2
3
var a, b int
var c string
a, b, c = 5, 7, "abc"

上面这行假设了变量 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 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。

阶段练习题

  1. package main的作用?

  2. 单行注释和多行注释分别是什么?

  3. 下面声明变量的方式错误的有哪些?

    1
    2
    3
    4
    5
    var name = "jerry"
    var age int = 18
    hobby = "嫂子"
    nickName string = "一米八大高个"
    webSite := "秃头统治地球"
    1
    2
    var age int = 18
    age = 19
  4. 下面声明变量的方式正确的有哪些?

    1
    2
    3
    4
    5
    6
    7
    8
    var v1,v2,v3 int
    var (
    v6 = 123
    v7 string
    )
    var v4,v5 = 11,22
    v4,v5 = 11,22
    v4,v5 := 11,22
  5. 变量名规范。

  6. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package main

    import "fmt"

    var number = 9999

    func main() {
    number := 666
    fmt.Println(number)
    }
  7. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package main

    import "fmt"

    var number = 99

    func main() {
    number := 66
    if true {
    number := 33
    fmt.Println(number)
    }
    fmt.Println(number)
    }
  8. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package main

    import "fmt"

    var number = 99

    func main() {
    number := 66
    if true {
    number := 33
    fmt.Println(number)
    }
    number = 88
    fmt.Println(number)
    }
  9. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package main

    import "fmt"

    var number = 99

    func main() {
    if true {
    fmt.Println(number)
    }
    number = 88
    fmt.Println(number)
    }
  10. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package main

    import "fmt"

    var number = 99

    func main() {
    number := 88
    if true {
    number = 123
    fmt.Println(number)
    }
    fmt.Println(number)
    }

  11. 看代码写结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import "fmt"

func main() {
// 整型
fmt.Println(666)
fmt.Println(6 + 9)
fmt.Println(6 - 9)
fmt.Println(6 * 9)
fmt.Println(16 / 9) // 商
fmt.Println(16 % 9) // 余数

// 字符串类型,特点:通过双引号
fmt.Println("jerry")
fmt.Println("钓鱼要掉刀鱼,刀鱼到岛上钓")
fmt.Println("gooo" + "SB")
//fmt.Println("gooo" + 666)
fmt.Println("gooo" + "666")
// 对比
fmt.Println("1" + "2") // 结果:"12"
fmt.Println(1 + 2) // 结果:3

// 布尔类型,真假
fmt.Println(1 > 2) // false 假
fmt.Println(1 < 2) // true 真
fmt.Println(1 == 2)
fmt.Println(1 >= 2)
fmt.Println("gooo" == "sb")

// 浮点型
var f32 float32 = 3.14159111111
var f64 float64 = 2.71828111111

fmt.Printf("float32: %f\n", f32)
fmt.Printf("float64: %f\n", f64)

// if判断
if 2 > 1 {
fmt.Println("叫爸爸")
} else {
fmt.Println("孙子")
}

}

整形

字节了解:

字节(Byte):计算机中数据储存的单位。

位(bit):也叫作“比特”,计算机中数据储存的最小单位,因为在计算机中是以二进制的形式数据储存,所以每个位以“0”或“1”表示。

位和字节的关系是:8个位组成一个字节。

字节与位的关系:1Byte=8bit。

img

  • 整形类型
具体类型取值范围
int8-128到127
uint80到255
int16-32768到32767
uint160到65535
int32-2147483648到2147483647
uint320到4294967295
int64-9223372036854775808到9223372036854775807
uint640到18446744073709551615
uint与平台相关,32位操作系统上就是uint32,64位操作系统上就是uint64
int与平台相关,32位操作系统上就是int32,64位操作系统上就是int64
1
2
3
var x int
x = 9223372036854775809
fmt.Print(x) // overflows int
  • 进制转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 十进制转化
var a int = 10
fmt.Printf("%d \n", a) // 10 占位符%d表示十进制
fmt.Printf("%b \n", a) // 1010 占位符%b表示二进制
fmt.Printf("%o \n", a) // 12 占位符%o表示八进制
fmt.Printf("%x \n", a) // a 占位符%x表示十六进制

// 八进制转化
var b int = 020
fmt.Printf("%o \n", b) // 20
fmt.Printf("%d \n", b) // 16
fmt.Printf("%x \n", b) // 10
fmt.Printf("%b \n", b) // 10000

// 十六进制转化
var c = 0x12
fmt.Printf("%d \n", c) // 18
fmt.Printf("%o \n", c) // 22
fmt.Printf("%x \n", c) // 12
fmt.Printf("%b \n", c) // 10010

浮点型

float类型分为float32float64两种类型,这两种浮点型数据格式遵循 IEEE 754 标准。

单精度浮点数占用4个字节(32位)存储空间来存储一个浮点数。而双精度浮点数使用 8个字节(64位)存储空间来存储一个浮点数。

单精度浮点数最多有7位十进制有效数字,如果某个数的有效数字位数超过7位,当把它定义为单精度变量时,超出的部分会自动四舍五入。双精度浮点数可以表示十进制的15位有效数字,超出的部分也会自动四舍五入。

浮点类型默认声明为float64。

1
2
3
4
5
6
7
8
9
10
var f1 float32 // float32:  单精度浮点型
f1 = 3.1234567890123456789
fmt.Println(f1, reflect.TypeOf(f1))

var f2 float64 // 双精度浮点型
f2 = 3.1234567890123456789
fmt.Println(f2, reflect.TypeOf(f2))

var f3 = 3.1234567890123456789
fmt.Println(f3, reflect.TypeOf(f2)) // 默认64

科学计数表示

1
2
3
4
5
var f1 = 2e10        // 即使是整数用科学技术表示也是浮点型
fmt.Println(f1,reflect.TypeOf(f1))

var f2 = 2e-2
fmt.Println(f2,reflect.TypeOf(f2))

布尔类型

布尔类型是最基本数据类型之一,只有两个值:true和false,分别代表逻辑判断中的真和假,主要应用在条件判断中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"reflect"
)

func main() {
var b bool // 声明b是一个布尔类型
b = true
b = false // 该类型只有true和false两个值,分别代表真假两种状态
fmt.Println(b, reflect.TypeOf(b))

fmt.Println(1 == 1) // 比较运算符的结果是一个布尔值
// fmt.Println(1 == "1") // 报错,mismatched types不能比较
fmt.Println(3 > 1)

var name = "yuan"
var b2 = name == "rain"
fmt.Println(b2)

}

字符串

字符串是最基本也是最常用的数据类型,是通过双引号将多个字符按串联起来的一种数据,用于展示文本。

1
2
var s = "hello yuan"  
fmt.Println(s)

单引号只能标识字符

字符串的基本操作

字符串在内存中是一段连续存储空间

截屏2022-07-23 20.58.43

注意:

  1. 索引从零开始计数
  2. go语言不支持负索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var s = "hello yuan"
fmt.Println(s)

// (1)索引取值 slice[index]
a:= s[2]
fmt.Println(string(a))

// (2)切片取值slice[start:end], 取出的元素数量为:结束位置 - 开始位置;
b1:=s[2:5] //
fmt.Println(b1)
b2:=s[0:] // 当缺省结束位置时,表示从开始位置到整个连续区域末尾;
fmt.Println(b2)
b3:=s[:8] // 当缺省开始位置时,表示从连续区域开头到结束位置;
fmt.Println(b3)

// (3)字符串拼接
var s1 = "hello"
var s2 = "yuan"
var s3 = s1 + s2 // 生成一个新的字符串
fmt.Println(s3)
转义符

Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。

转义符含义
\r回车符(返回行首)
\n换行符(直接跳到下一行的同列位置)
\t制表符
\'单引号
\"双引号
\\反斜杠

举个例子,我们要打印一个Windows平台下的一个文件路径:

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
var s1 = "hi yuan\nhi,alvin"
fmt.Println(s1)
var s2 = "his name is \"rain\""
fmt.Println(s2)
var s3 = "D:\\next\\go.exe"
fmt.Println(s3)
}
多行字符串

Go语言中要定义一个多行字符串时,就必须使用反引号字符:

1
2
3
4
5
s1 := `第一行
第二行
第三行
`
fmt.Println(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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
"fmt"
"reflect"
"strings"
)

func main() {
s := "hello world"
// fmt.Println(len(s))
// strings.ToUpper 和 strings.ToLower
s1 := strings.ToUpper("Yuan")
s2 := strings.ToLower("Rain")
fmt.Println(s1, s2)

// strings.Trim
user := " yuan "
fmt.Println(len(user))
fmt.Println(strings.TrimLeft(user, " "))
fmt.Println(strings.TrimSpace(user))
fmt.Println(strings.Trim(user, " "))

s := "alvin,yuan,eric"
// strings.Index,strings.LastIndex
var index = strings.Index(s, "yuan!")
fmt.Println(index) // 未找到返回-1
var index2 = strings.LastIndex(s, "l")
fmt.Println(index2)

// strings.HasPrefix,strings.HasSuffix,strings.Contains(实现的依赖的就是strings.Index)
fmt.Println(strings.HasPrefix(s, "alv"))
fmt.Println(strings.HasSuffix(s, "eric"))
fmt.Println(strings.Contains(s, "eric"))

// strings.Split: 将字符串分割成数组
var ret2 = strings.Split(s, ",")
fmt.Println(ret2, reflect.TypeOf(ret2))

// strings.Join:将数组拼接成字符串
var ret3 = strings.Join(ret2, "-")
fmt.Println(ret3, reflect.TypeOf(ret3))

Go 常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。在Python、Java编程规范中,常量⼀般都是全⼤写字母,但是在Golang中,⼤⼩写是具有⼀定特殊含义的,所以不⼀定所有常量都得全⼤写。

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量的定义格式:

1
const 常量名[数据类型] = value

数据类型可以忽略不写,Golang编译器会⾃动推断出数据类型。 在使⽤时,要注意以下⼏点:

  1. 数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
  2. 满⾜多重赋值
  3. 常量只定义不使⽤,编译不会报错
  4. 常量可以作为枚举,常量组
  5. 常量组中如不指定类型和初始化值,则与上⼀⾏⾮空常量右值相同
  6. 显⽰指定类型的时候,必须确保常量左右值类型⼀致,需要时可做显⽰类型转换。

多个相同类型的声明可以简写为:

1
const c_name1, c_name2 = value1, value2

常量的应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
const LENGTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" // 多重赋值

area = LENGTH * WIDTH
fmt.Printf("面积为: %d", area)
println()
println(a, b, c)
}

以上实例运行结果为:

1
2
面积为 : 50
1 false str

常量还可以用作枚举:

1
2
3
4
5
const (
Unknown = 0
Female = 1
Male = 2
)

因式分解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import "fmt"


func main() {
// 定义变量
//var name string = "jerry"
//var name = "jerry"
name := "jerry"
name = "gooo"
fmt.Println(name)

// 定义常量
//const age int = 98
const age = 98
fmt.Println(age)

// 常量因式分解
const (
v1 = 123
v2 = 456
pi = 9.9
)
fmt.Println(v1, v2, pi)
}

全局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import "fmt"

const Data = 999
const (
pi = 3.1415926
gender = "男"
)

func main() {
// 定义变量
//var name string = "jerry"
//var name = "jerry"
name := "jerry"
name = "gooo"
fmt.Println(name)

// 定义常量
//const age int = 98
const age = 98
fmt.Println(age)

// 常量因式分解
const (
v1 = 123
v2 = 456
//pi = 9.9
)
fmt.Println(v1, v2, pi, gender)
}

// gooo
// 98
// 123 456 3.1415926 男

iota

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值:

1
2
3
4
5
const (
a = iota
b = iota
c = iota
)

第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:

1
2
3
4
5
const (
a = iota
b
c
)

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package main

const (
monday = iota + 1
tuesday
wednesday
thursday
friday
saturday
sunday
)

const (
n1 = iota
n2
n3
)

func main() {

// iota
// 示例1
/*
const (
v1 = 1
v2 = 2
v3 = 3
v4 = 4
v5 = 5
)
fmt.Println(v1, v2, v3, v4, v5)
*/

// 示例2
/*
const (
v1 = iota
v2
v3
v4
v5
)
fmt.Println(v1, v2, v3, v4, v5)
*/

// 示例3
/*
const (
v1 = iota + 2
v2
v3
v4
v5
)
fmt.Println(v1, v2, v3, v4, v5)
*/

// 示例4:
/*
const (
v1 = iota + 2
_
v2
v3
v4
v5
)
fmt.Println(v1, v2, v3, v4, v5)
*/

}

更有趣的iota实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i) // 0 1 2 ha ha 100 100 7 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)

func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}

i= 1
j= 6
k= 12
l= 24

iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2l=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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import "fmt"

func main() {

   var a int = 21
   var b int = 10
   var c int

   c = a + b
   fmt.Printf("第一行 - c 的值为 %d\n", c )
   c = a - b
   fmt.Printf("第二行 - c 的值为 %d\n", c )
   c = a * b
   fmt.Printf("第三行 - c 的值为 %d\n", c )
   c = a / b
   fmt.Printf("第四行 - c 的值为 %d\n", c )
   c = a % b
   fmt.Printf("第五行 - c 的值为 %d\n", c )
   a++
   fmt.Printf("第六行 - a 的值为 %d\n", a )
   a=21   // 为了方便测试,a 这里重新赋值为 21
   a--
   fmt.Printf("第七行 - a 的值为 %d\n", a )
}
第一行 - c 的值为 31
第二行 - c 的值为 11
第三行 - c 的值为 210
第四行 - c 的值为 2
第五行 - c 的值为 1
第六行 - a 的值为 22
第七行 - a 的值为 20

关系运算符

下表列出了所有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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import "fmt"

func main() {
   var a int = 21
   var b int = 10

   if( a == b ) {
      fmt.Printf("第一行 - a 等于 b\n" )
   } else {
      fmt.Printf("第一行 - a 不等于 b\n" )
   }
   if ( a < b ) {
      fmt.Printf("第二行 - a 小于 b\n" )
   } else {
      fmt.Printf("第二行 - a 不小于 b\n" )
   }
   
   if ( a > b ) {
      fmt.Printf("第三行 - a 大于 b\n" )
   } else {
      fmt.Printf("第三行 - a 不大于 b\n" )
   }
   /* Lets change value of a and b */
   a = 5
   b = 20
   if ( a <= b ) {
      fmt.Printf("第四行 - a 小于等于 b\n" )
   }
   if ( b >= a ) {
      fmt.Printf("第五行 - b 大于等于 a\n" )
   }
}
第一行 - a 不等于 b
第二行 - a 不小于 b
第三行 - a 大于 b
第四行 - a 小于等于 b
第五行 - b 大于等于 a

逻辑运算符

下表列出了所有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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import "fmt"

func main() {
   var a bool = true
   var b bool = false
   if ( a && b ) {
      fmt.Printf("第一行 - 条件为 true\n" )
   }
   if ( a || b ) {
      fmt.Printf("第二行 - 条件为 true\n" )
   }
   /* 修改 a 和 b 的值 */
   a = false
   b = true
   if ( a && b ) {
      fmt.Printf("第三行 - 条件为 true\n" )
   } else {
      fmt.Printf("第三行 - 条件为 false\n" )
   }
   if ( !(a && b) ) {
      fmt.Printf("第四行 - 条件为 true\n" )
   }
}
第二行 - 条件为 true
第三行 - 条件为 false
第四行 - 条件为 true

位运算符

位运算符对整数在内存中的二进制位进行操作。

下表列出了位运算符 &, |, 和 ^ 的计算:

pqp & qp l qp ^ q
00000
01011
11110
10011

假定 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import "fmt"

func main() {

   var a uint = 60      /* 60 = 0011 1100 */  
   var b uint = 13      /* 13 = 0000 1101 */
   var c uint = 0          

   c = a & b       /* 12 = 0000 1100 */
   fmt.Printf("第一行 - c 的值为 %d\n", c )

   c = a | b       /* 61 = 0011 1101 */
   fmt.Printf("第二行 - c 的值为 %d\n", c )

   c = a ^ b       /* 49 = 0011 0001 */
   fmt.Printf("第三行 - c 的值为 %d\n", c )

   c = a << 2     /* 240 = 1111 0000 */
   fmt.Printf("第四行 - c 的值为 %d\n", c )

   c = a >> 2     /* 15 = 0000 1111 */
   fmt.Printf("第五行 - c 的值为 %d\n", c )
}
第一行 - c 的值为 12
第二行 - c 的值为 61
第三行 - c 的值为 49
第四行 - c 的值为 240
第五行 - c 的值为 15

必知必会概念:

位运算指的是二进制之间的运算:

  • 计算机中的 存储、运算、网络传输等任何的行为,本质上都是二进制的操作。例如:01010101。

    1
    2
      A				                  B
    hello -> 0101010010101 -> hello
  • 信息表现形式

    1
    2
    二进制表示:0101010010101   ->  hello
    十进制表示:1921 -> hello
  • 十进制和二进制的转换关系

    十进制二进制
    00
    11
    210
    311
    4100
    5101
    6110
    7111
    81000
    91001
    101010
  • 二进制转换为十进制

    1
    2
    10101         ->   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
2
3
4
5
6
7
8
9
10
1 行 - =  运算符实例,c 值为 = 21
2 行 - += 运算符实例,c 值为 = 42
3 行 - -= 运算符实例,c 值为 = 21
4 行 - *= 运算符实例,c 值为 = 441
5 行 - /= 运算符实例,c 值为 = 21
6行 - <<= 运算符实例,c 值为 = 800
7 行 - >>= 运算符实例,c 值为 = 200
8 行 - &= 运算符实例,c 值为 = 0
9 行 - ^= 运算符实例,c 值为 = 2
10 行 - |= 运算符实例,c 值为 = 2

其他运算符

下表列出了Go语言的其他运算符。

运算符描述实例
&返回变量存储地址&a; 将给出变量的实际地址。
*指针变量。*a; 是一个指针变量

以下实例演示了其他运算符的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import "fmt"

func main() {
   var a int = 4
   var b int32
   var c float32
   var ptr *int

   /* 运算符实例 */
   fmt.Printf("第 1 行 - a 变量类型为 = %T\n", a );
   fmt.Printf("第 2 行 - b 变量类型为 = %T\n", b );
   fmt.Printf("第 3 行 - c 变量类型为 = %T\n", c );

   /*  & 和 * 运算符实例 */
   ptr = &a     /* 'ptr' 包含了 'a' 变量的地址 */
   fmt.Printf("a 的值为  %d\n", a);
   fmt.Printf("*ptr 为 %d\n", *ptr);
}
1 行 - a 变量类型为 = int
2 行 - b 变量类型为 = int32
3 行 - c 变量类型为 = float32
a 的值为 4
*ptr 为 4

运算符优先级

有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

优先级运算符
5* / % << >> & &^
4+ - | ^
3== != < <= > >=
2&&
1||

当然,你可以通过使用括号来临时提升某个表达式的整体运算优先级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import "fmt"

func main() {
   var a int = 20
   var b int = 10
   var c int = 15
   var d int = 5
   var e int;

   e = (a + b) * c / d;      // ( 30 * 15 ) / 5
   fmt.Printf("(a + b) * c / d 的值为 : %d\n",  e );

   e = ((a + b) * c) / d;    // (30 * 15 ) / 5
   fmt.Printf("((a + b) * c) / d 的值为  : %d\n" ,  e );

   e = (a + b) * (c / d);   // (30) * (15/5)
   fmt.Printf("(a + b) * (c / d) 的值为  : %d\n",  e );

   e = a + (b * c) / d;     //  20 + (150/5)
   fmt.Printf("a + (b * c) / d 的值为  : %d\n" ,  e );  
}
(a + b) * c / d 的值为 : 90
((a + b) * c) / d 的值为 : 90
(a + b) * (c / d) 的值为 : 90
a + (b * c) / d 的值为 : 50

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

func main() {
// 示例1:fmt.Scan
/*
var name string
fmt.Println("请输入用户名:")
fmt.Scan(&name)
fmt.Printf(name)
*/

// 示例2:fmt.Scan
var name string
var age int

fmt.Println("请输入用户名:")
// 当使用Scan时,会提示用户输入
// 用户输入完成之后,会得到两个值:count,用户输入了几个值;err,用输入错误则是错误信息
_, err := fmt.Scan(&name, &age) // 输入类型不一致,按默认值
if err == nil {
fmt.Println(name, age)
} else {
fmt.Println("用户输入数据错误", err)
}
// 特别说明:fmt.Scan 要求输入两个值,必须输入两个,否则他会一直等待。
}

fmt.Scanln

语法

1
func Scanln(a ...interface{}) (n int, err error)
  • Scanln类似于Scan,它遇到换行立即停止扫描。
  • 本函数返回成功扫描的数据个数和遇到的任何错误。

Scanln和Scan的区别就是Scanln遇到换行立即结束输入,而Scan则会将换行符作为一个空白符继续下一个输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
// 示例1:fmt.Scanln
/*
var name string
fmt.Print("请输入用户名:")
fmt.Scanln(&name)
fmt.Printf(name)
*/

// 示例2:fmt.Scanln

var name string
var age int
fmt.Print("请输入用户名:")
// 当使用Scanln时,会提示用户输入
// 用户输入完成之后,会得到两个值:count,用户输入了几个值;err,用输入错误则是错误信息
count, err := fmt.Scanln(&name, &age)
fmt.Println(count, err)
fmt.Println(name, age)

// 特别说明:fmt.Scanln 等待回车。
}

fmt.Scanf

语法

1
func Scanfformat string, a ...interface{})(n int, err error)
  • Scanf从标准输入扫描文本,根据format参数指定的格式去读取由空白符分隔的值保存到传递给本函数的参数中。
  • 本函数返回成功扫描的数据个数和遇到的任何错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 案例1
var (
name1 string
age1 int
isMarried bool
)
fmt.Println("按照一下格式输入:\n 1:%s 2:%d 3:%t")
fmt.Scanf("1:%s 2:%d 3:%t", &name1, &age1, &isMarried) // 必须按照这个格式输入1:%s 2:%d 3:%t
fmt.Printf("扫描结果 姓名:%s 年龄:%d 婚否:%t", name1, age1, isMarried)

//按照一下格式输入:
//1:%s 2:%d 3:%t
//1:jerry 2:11111 3:true
//扫描结果 姓名:jerry 年龄:11111 婚否:true


// 案例2
var name string
var age int

fmt.Print("请输入用户名:")
fmt.Scanf("我叫%s 今年%d 岁", &name, &age)
fmt.Println(name, age)

//请输入用户名:我叫jerr 今年18岁
//jerr 18

Go 知识点总结

  1. fmt.Print函数用于将格式化的字符串输出到标准输出(通常是终端)。它的语法如下:
1
fmt.Println("Hello, World!") // 输出: Hello, World!
  1. fmt.Printf(): 用于按照指定的格式将参数格式化为字符串并打印到标准输出。
1
2
3
name := "Alice"  
age := 25
fmt.Printf("My name is %s and I'm %d years old.\n", name, age) // 输出: My name is Alice and I'm 25 years old.
  1. fmt.Scanf(): 用于从标准输入读取数据并根据指定的格式进行解析。
1
2
3
4
var name string  
var age int
fmt.Scanf("Enter your name: %s\nEnter your age: %d\n", &name, &age) // 读取用户输入并解析
fmt.Printf("Name: %s, Age: %d\n", name, age) // 输出: Name: Alice, Age: 25
  1. fmt.Fprintf(): 用于将格式化的数据写入到指定的io.Writer中。
1
2
3
file, _ := os.Create("output.txt") // 创建一个文件用于写入  
fmt.Fprintf(file, "This is some text.\n") // 将文本写入文件
file.Close() // 关闭文件