风在路上 风在路上
首页
导航站
  • Java-Se

    • Java基础
  • Java-Se进阶-多线程

    • 多线程
  • Java-Se进阶-java8新特性

    • java8新特性
  • Java-ee

    • JavaWeb
  • Java虚拟机

    • JVM
  • golang基础

    • golang基础
  • golang框架

    • gin
  • SQL 数据库

    • MySQL
  • NoSQL 数据库

    • Redis
    • ElasticSearch
    • MongoDB
  • ORM

    • MyBatis
    • MyBatis-Plus
  • Spring

    • Spring
  • SpringMVC

    • SpringMVC1
    • SpringMVC2
  • SpringCloud

    • SpringCloud
  • 中间件

    • RabbitMQ
    • Dubbo
  • 秒杀项目
  • Git
  • Linux
  • Docker
  • JWT
  • 面试
  • 刷题
开发问题😈
设计模式
关于💕
归档🕛
GitHub (opens new window)

风

摸鱼
首页
导航站
  • Java-Se

    • Java基础
  • Java-Se进阶-多线程

    • 多线程
  • Java-Se进阶-java8新特性

    • java8新特性
  • Java-ee

    • JavaWeb
  • Java虚拟机

    • JVM
  • golang基础

    • golang基础
  • golang框架

    • gin
  • SQL 数据库

    • MySQL
  • NoSQL 数据库

    • Redis
    • ElasticSearch
    • MongoDB
  • ORM

    • MyBatis
    • MyBatis-Plus
  • Spring

    • Spring
  • SpringMVC

    • SpringMVC1
    • SpringMVC2
  • SpringCloud

    • SpringCloud
  • 中间件

    • RabbitMQ
    • Dubbo
  • 秒杀项目
  • Git
  • Linux
  • Docker
  • JWT
  • 面试
  • 刷题
开发问题😈
设计模式
关于💕
归档🕛
GitHub (opens new window)
  • 基础

    • golang基础
    • 安装
    • 基本语法
      • 基础
        • hello world
        • 变量
        • 定义
        • 多个定义
        • 短变量声明并初始化
        • 变量交换
        • 匿名变量
        • 变量的作用域
        • 局部变量
        • 全局变量
        • 常量
        • iota
        • 基本数据类型
        • 布尔
        • 数字
        • 整型
        • 浮点型
        • 字符串
        • 数据类型转换
        • 运算符
        • 键盘交互
      • 流程控制
        • if
        • switch
        • fallthrough
        • for
      • 数组/Slice
        • 固定长度数组
        • 切片
        • 声明方式
        • 追加
        • 截取
      • map
        • 定义方式
        • 使用方式
    • 函数
    • 面向对象
    • Goroutine
  • golang
  • 基础
zdk
2023-04-22
目录

基本语法

# 基本语法

# 基础

# hello world

众所周知,学习一门语言最开始就是输出一句hello world,下面使用Goland实现

这里创建名为study-demo的项目,在根目录下创建hello.go文件

package main

import "fmt"

func main() {
	fmt.Println("hello world!")
}

1
2
3
4
5
6
7
8

运行即可查看结果:

image-20230422201743010

上述代码的相关解释:

  1. 在Go语言里,命名为 main的包具有特殊的含义。Go语言的编译程序会试图把这种名字的包编译为二进制可执行文件。所有用Go语言编译的可执行程序都必须有一个名叫 main的包。一个可执行程序有且仅有一个main包。当编译器发现某个包的名字为main时,它一定也会发现名为main()的函数,否则不会创建可执行文件。main()函数是程序的入口,所以,如果没有这个函数,程序就没有办法开始执行。程序编译时,会使用声明main包的代码所在的目录的目录名作为二进制可执行文件的文件名。
  2. 这里的import类似于java中的import,就是导入一些官方库或第三方库

# 变量

# 定义

var name string = "test"
name = "zdk"
1
2

var表示定义变量,在变量第一次声明时,必须存在,再次对变量赋值时,即可省略。这里如果定义的变量不使用,goland会提示报错

  • var是声明变量的关键字,固定写法
  • 第二个name是变量的名称
  • 第三个string是变量的类型
  • =号后即是变量值

这里其实可以发现它和java的写法是相反的

package main

import "fmt"

func main() {
	var name string = "test"
	name = "zdk"
	fmt.Println(name)
	var username string = "zdk"
	username = "111"
	fmt.Println(username)
}

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

# 多个定义

package main

import "fmt"

func main() {
	var (
		id       int
		password string
		age      int
	)
    //在未初始化时,输出的是语言设定类型的默认值
	fmt.Println(id, password, age)
    //输出:0  0  中间是空白的 string的默认值是""
    
    // 这种方式可以打印变量的内存地址 &和c一样 为取地址符
    fmt.Printf("username的值:%s,地址:%p\n", username, &username)
    //username的值:111,地址:0xc00004c280
}

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

var形式的声明语句往往是用于需要显式指定变量类型地方,或者因为变量稍后会被重新赋值而初始值无关紧要的地方。当一个变量被声明之后,如果没有显示的给变量赋值,系统自动赋予它该类型的默认值:

  • 整型和浮点型变量的默认值为0和0.0。
  • 字符串变量的默认值为空字符串。
  • 布尔型变量默认为false。
  • 切片、函数、指针变量的默认为nil。

# 短变量声明并初始化

package main

import "fmt"

func main() {
	name := "xxx"
    age := 18
}

1
2
3
4
5
6
7
8
9

可以使用 变量名 := 变量值的方式简化变量定义,编译器会根据变量值推导变量类型

这是Go语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。

它可以自动的推导出一些类型,但是使用也是有限制的;

  • 定义变量,同时显式初始化。

  • 不能提供数据类型。

  • 只能用在函数内部。不能随便到处定义

因为简洁和灵活的特点,简短变量声明被广泛用于大部分的局部变量的声明和初始化。 注意:由于使用了:=,而不是赋值的=,因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。

# 变量交换

	var a int = 100
	var b int = 200
	a, b = b, a
	fmt.Println(a, b)
1
2
3
4

可使用以上方式方便地交换变量值

# 匿名变量

匿名变量的特点是一个下画线" _"," _"本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。例如:

package main

import "fmt"

func test() (int, int) {
	return 100, 200
}

func main() {

	a, _ := test()
	_, b := test()

	//输出结果为 100 200
	fmt.Println(a, b)

	// 在第一行代码中 我们只需要第一个返回值 所以第二个返回值为匿名变量
	// 在第二行代码中 我们只需要第二个返回值 所以第一个返回值为匿名变量
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在编码过程中,可能会遇到没有名称的变量、类型或方法。虽然这不是必须的,但有时候这样做可以极大地增强代码的灵活性,这些变量被统称为匿名变量。

匿名变量不占用内存空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。

# 变量的作用域

一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。

了解变量的作用域对我们学习Go语言来说是比较重要的,因为Go语言会在编译时检查每个变量是否使用过,一旦出现未使用的变量,就会报编译错误。如果不能理解变量的作用域,就有可能会带来一些不明所以的编译错误。

# 局部变量

在函数体内部声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量都属于局部变量。

package main
import (
	"fmt"
)

func main(){
    //声明局部变量a和b
    var a int = 3
    var b int = 4
    //声明局部变量c
    c := a + b
    fmt.Printf("a = %d, b = %d, c = %d\n",a, b, b)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
# 全局变量

在函数体外声明的变量称之为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用"import"关键字引入全局变量所在的源文件之后才能使用这个全局变量。 全局变量声明必须以var关键字开头,如果想要在外部包中使用全局变量的首字母必须大写。

package main

import (
	"fmt"
)

var name string = "zdk"

func main() {
	var name string = "2222"
	fmt.Println(name)
}
1
2
3
4
5
6
7
8
9
10
11
12

在go语言中,全局变量和局部变量可以使用相同的名称,但是在调用时会优先调用局部变量

# 常量

常量时一个简单值的标识符,在程序运行时,不会被修改的值。

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

const identifier [type] = value
1

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

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

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

const c_name1, c_name2 = value1, value2
1

示例:

package main

func main() {
	const URL = "www.baidu.com"
	const PI = 3.14

	const LENGTH = 10
	const WIDTH int = 5
	//多重赋值
	const a, b, c = 1, false, "str"
}
1
2
3
4
5
6
7
8
9
10
11
# iota

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

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

iota可以被用作枚举值

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

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

const(
    //一组常量中,如果某个常量没有初始值,默认和上一行的常量一致
	a = iota
    b
    c
)
1
2
3
4
5
6

代码示例:

package main

import "fmt"

func main() {
	const (
		a = iota
		b
		c
		d = "haha"
		e
		f = 100
		g
		h = iota
		i
	)
	const (
		j = iota
		k
	)
	fmt.Println(a, b, c, d, e, f, g, h, i)
	//输出 0 1 2 haha haha 100 100 7 8
	fmt.Println(a, b, c, d, e, f, g, h, i, j, k)
	//输出 0 1 2 haha haha 100 100 7 8 0 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

这里表示,iota是一直在增加的,它其实就是const语句块中常量的数量,然后体现了未赋值时,常量的值等于它上一个常量的值。

而每个const块中的iota都从0开始,所以两个const块之间的iota并无关系

# 基本数据类型

# 布尔

package main

import "fmt"

func main() {

	//布尔值demo 默认值是false
	var flag bool = true

	fmt.Println(flag)

	// 输出 类型:bool,值:true
	fmt.Printf("类型:%T,值:%t\n", flag, flag)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 数字

整型int和浮点型float32,float64,Go语言支持整型和浮点型数字,并且支持复数,其中的位运算采用补码。

Go也有基于架构的类型,例如:uint无符号、int有符号

# 整型

序号 类型和描述
1 unint8无符号8位整型(0~255)
2 unint16无符号16位整型(0~65535)
3 unint32无符号32位整型(0~4294967295)
4 unint64无符号64位整型(0~18446744073709551615)
5 int8有符号8位整型(-128~127)
6 int16有符号16位整型(-32768~32767)
7 int32有符号32位整型(-2147483648~2147483647)
8 int64有符号64位整型(-9223372036854775808~9223372036854775807)

# 浮点型

编号 类型和描述
1 float32IEEE-754 32位浮点型数
2 float64IEEE-754 64位浮点型数
3 comples6432位实数和虚数
4 comples12864位实数和虚数
  1. 关于浮点数在机器中存放形式的简单说明,浮点数=符号位+指数位+尾数位
  2. 尾数部分可能丢失,造成精度损失。-123.0000901
  3. golang的浮点型默认为float64
  4. 通常情况下,应该使用float64,因为它比float32更精确(保存精度高的数)

以下列出了其他更多的数字类型:

序号 类型和描述
1 byte类似uint8
2 rune类型int32
3 uint32或64位
4 int与uint一样大小
5 uintptr无符号整型,用于存放一个指针

# 字符串

这里不过多赘述,使用""定义时,变量类型为string,使用''定义时,变量类型实为int32,表示字符在ASCII码表中对应的值

字符串连接同样使用 + 号

# 数据类型转换

在必要以及可行的情况下,一个类型的值可以被转换成另一种类型的值。由于Go不存在隐式类型转换,因此所有的类型转换都必须显式地声明:

valueOfTypeB = typeB(valueOfTypeA)
1

类型A变量转为类型B -> 即 类型B的值 = 类型B(类型A的值)

func main(){
    a := 5.0
    b := int(a)
    
    fmt.Printf("%T,%f\n",a,a)
    fmt.Printf("%T,%d\n",b,b)
}
1
2
3
4
5
6
7

类型转换只能在定义正确的情况下转换成功,例如从一个取值范围较小的类型转换到一个取值范围较大的类型(将int16转换为int32)。当从一个取值范围较大的类型转换到取值范围较小的类型时(将int32转换为int16或将float32转换为 int),会发生精度丢失(截断)的情况。

# 运算符

基本和java一致 不赘述

# 键盘交互

package main

import "fmt"

func main() {

	var x, y int

	fmt.Scanln(&x, &y)

	fmt.Println("x:", x)
	fmt.Println("y:", y)
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 流程控制

# if

if、else、else if这些与java的差不多,只是判断条件不用括号括住

func main(){
    x := 10
    y := 20
    if x > y {
        //操作
    }else {
        //操作
    }
}
1
2
3
4
5
6
7
8
9

# switch

switch var1 {
    case value1:
    	...
    case value2:
    	...
    default:
    	...
}
1
2
3
4
5
6
7
8

匹配项后面不需要再加break,switch默认情况下case最后自带break语句

switch {
    case true:
    	...
    case false:
    	...
    default:
    	...
}
1
2
3
4
5
6
7
8

这里switch后面没有变量,其实表示 switch true,即判断是否为true

# fallthrough

switch默认情况下匹配成功后不会执行其他case,如果我们需要执行后面的case,可以使用fallthrough穿透case,可以强制执行后面的case语句,fallthrough不会判断下一条case的表达式结果是否为true

package main

import "fmt"

func main() {

	a := 1

	switch a {
	case 1:
		fmt.Println("1111")
		fallthrough
	case 2:
		fmt.Println("2222")
	case 3:
		fmt.Println("333")
	case 4:
		fmt.Println("4444")
	default:
		fmt.Println("default")
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

上述代码输出:

1111 2222

表明了添加了fallthrough的case,只会穿透到它的下一个case,并不会穿透后面的所有case,同时满足case后default是不执行的(和java一样)

# for

for i := 0; i < 10; i++ {
		
}
1
2
3

与java区别只是for后面的语句不加括号,类比上面的if

还有go提供的其他循环方式

package main

import "fmt"

func main() {
	str := "jdasijd"
    
    for i := 0; i < len(str); i++ {
        //这样打印其实打印的是字符在ASCII码表中的数字
		fmt.Print(str[i])
        // uint8
        fmt.Printf("%T",str[i])
	}

    	// 只写一个变量 默认就是下标
	for index := range str {
		fmt.Print(index)
	}
    
    // 两个变量就是 下标 值
	for index, element := range str {
		fmt.Print(index)
		//这样打印其实打印的是字符在ASCII码表中的数字
		fmt.Print(element)
		fmt.Printf("%c\n", element)
	}
    
    // 只需要值时可以使用匿名变量
	for _, value := range str {
		fmt.Print(element)
		fmt.Printf("%c\n", element)
	}
}

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

上面代码中的str[i]的类型实际是uint8

# 数组/Slice

# 固定长度数组

//固定长度的数组
var arr1 [10]int
arr1 = [10]int{1, 2, 3}
fmt.Println(arr1)
1
2
3
4

# 切片

//切片 类型是 []int
var arr2 = []int{11, 22, 32}
fmt.Printf("%T\n", arr2)
for _, value := range arr2 {
	fmt.Println(value)
}
1
2
3
4
5
6

在使用时操作和数组是完全一样的。且在被传递到函数中的时候,就不再是值拷贝了,而是引用传递,在函数中修改会被应用

# 声明方式

// 声明slice的方式
//1. 以下的声明方式 var定义后 slice还没有被赋予地址
// 它是 len = 0,slice1 = []
var slice1 []int
fmt.Printf("len = %d,slice1 = %v\n", len(slice1), slice1)
if slice1 == nil {
	fmt.Println("slice1是nil")
} else {
	fmt.Println("bushi")
}
// 使用make开辟3个int类型的长度的地址空间后 是 len = 3,slice1 = [0 0 0]
slice1 = make([]int, 3)
fmt.Printf("len = %d,slice1 = %v\n", len(slice1), slice1)
//2.显式直接声明 这里前面的[]int可省略 因为类型推断
var slice2 []int = []int{1, 2, 3}
fmt.Printf("len = %d,slice2 = %v\n", len(slice2), slice2)
//3.方式1的直接赋值
slice3 := make([]int, 3)
fmt.Printf("len = %d,slice3 = %v\n", len(slice3), slice3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

make的第二个参数表示初始化的长度,第三个参数表示容量,如果第三参数不写,则默认等于第二个参数

var numbers []int = make([]int, 3, 5)
fmt.Printf("len = %d,cap = %d", len(numbers), cap(numbers))
1
2

输出:len = 3,cap = 5

image-20230424174620198

# 追加

使用append方法对切片进行追加元素,参数2是可变参数,即可追加多个元素到末尾 但不能超过cap

//向numbers追加元素,参数2是可变参数,即可追加多个元素到末尾
numbers = append(numbers, 1)
fmt.Printf("len = %d,cap = %d\n", len(numbers), cap(numbers))
// len = 4,cap = 5 {0,0,0,1}
1
2
3
4

当此时的len已经达到cap,想要再次添加元素的时候,go会将numbers扩容为原来cap的2倍

numbers = append(numbers, 22, 33, 44)
fmt.Printf("len = %d,cap = %d\n", len(numbers), cap(numbers))
// len = 7,cap = 10
1
2
3

实际是重新开辟了内存,然后将原来的拷贝过去再append

# 截取

使用 切片[start:end]的方式进行截取,截取内容是下标左闭右开[start,end)

sub1 := numbers[0:2]
sub1[0] = 10086
fmt.Println("修改后numbers:", numbers)
fmt.Println("修改后sub1:", sub1)
//修改后numbers: [10086 0 0 1 22 33 44]
//修改后sub1: [10086 0]
1
2
3
4
5
6

这种截取方式实质两者还是指向同一个地址,修改时都会修改

# map

# 定义方式

package main

import "fmt"

func main() {

	var map1 map[string]string

	map1 = make(map[string]string, 10)

	str := "zdk"

	map1[str] = "111"

	fmt.Println("map1[str]:", map1[str])
	// 或者 添加时会自动扩容
	map2 := make(map[string]string)
	fmt.Println("map2:", map2)

	// 或者显式值声明
	map3 := map[string]string{
		"one":   "php",
		"two":   "c++",
		"three": "python",
	}
	fmt.Println("map3:", map3)
}
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 printMap(mapData map[int]string) {
	for key, value := range mapData {
		fmt.Println("key = ", key)
		fmt.Println("value = ", value)
	}
}

func main() {
	userMap := make(map[int]string)
	//添加
	userMap[1] = "zdk1"
	userMap[2] = "zdk2"
	userMap[3] = "zdk3"
	userMap[4] = "zdk4"
	//遍历
	printMap(userMap)
	//删除
	delete(userMap, 1)
	//修改
	userMap[3] = "woshi3545"
	fmt.Println("-----------------")
	printMap(userMap)
}
/** 输出
key =  1
value =  zdk1    
key =  2         
value =  zdk2    
key =  3         
value =  zdk3    
key =  4         
value =  zdk4    
-----------------
key =  2         
value =  zdk2
key =  3
value =  woshi3545
key =  4
value =  zdk4
*/
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
在 GitHub 上编辑此页 (opens new window)
#golang
最后更新: 2023/04/25, 20:04:00
安装
函数

← 安装 函数→

Theme by Vdoing | Copyright © 2022-2025 zdk | notes
湘ICP备2022001117号-1
川公网安备 51142102511562号
本网站由 提供CDN加速/云存储服务
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式