go语言基础语法

go语言基础语法

运行第一个Go程序

go 复制代码
package main
import "fmt"
func main(){

	fmt.Println("Hello, World!")
	
}

运行go程序:

bash 复制代码
# 方法1:
go run hello.go

这种方式运行go程序,不会生成二进制文件,而是直接运行!

bash 复制代码
# 方法2
go build hello.go
./hello

这种方式是先通过go build命令将hello.go编译成一个可执行二进制文件,然后再通过运行这个二进制文件来运行我们的go程序。

go语言目录结构

Go 社区推荐并遵循一个被称为 "Standard Go Project Layout" 的结构。虽然这不是 Go 官方工具链强制要求的,但绝大多数 Go 项目和工具(如包管理、构建脚本)都默认为这种结构。

核心目录结构:

目录名 作用&描述 强制性
cmd/ 主应用 (Main Applications):存放所有可执行应用程序的源代码。每个子目录通常对应一个独立的可执行文件(即一个 package main)。 约定
pkg/ 公共库代码 (Library Code):存放可以被外部应用导入使用的库代码。它不应该包含任何 package main 的代码。 约定
internal/ 内部库代码 (Private Library Code):存放只供当前项目内部使用,禁止被外部项目导入的代码。Go 工具链会强制阻止外部导入这个目录下的代码。 强制执行 (Go 1.4+)
api/ **API 规范:**存放 API 规范文件,如 OpenAPI/Swagger 规范、Protocol Buffers 定义文件等。 约定

建议工程项目按照这样的文件目录结构来进行维护,否则你的项目将难以被其他 Go 开发者理解和维护,也可能与标准的 Go 工具链、IDE 或第三方工具(如 Linters)集成不佳。因此,强烈建议遵循。

基础语法

行分隔符

在go语言程序中,每一句程序,无须手动添加;来表示结尾,编译器会手动为你添加,当让你非要手动添加,编译器也不会报错;

但是如果你在一行中写了多条语句,那么这时候必须强制为每一条语句加上;表示结尾,不要编译会报错;

go 复制代码
# 编译不会报错
fmt.Println("hello");

# 编译不会报错
fmt.Println("hello")

# 编译不会报错
fmt.Println("hello"); fmt.Println("hello"); fmt.Println("hello");

# 编译会报错
fmt.Println("hello") fmt.Println("hello") fmt.Println("hello")

注释

go语言注释和C/C++注释风格一致;

go 复制代码
// 这表示一个单行注释

/*
这是一个注释块

*/

标识符

go语言的标识符命名规则与其他语言一致,允许使用字母、数字、下划线;

  1. 但是第一个字符必须是字母
  2. 如果想要一个全局变量、函数、类被外部包访问,则首字母必需大写!首字母小写表示不可被外部包导入!

字符串拼接

go语言支持使用+来拼接两个字符串:

go 复制代码
package main

import "fmt"

func main() {
	// 输出结果helloworld
	fmt.Println("hello" + "world")

}
go 复制代码
// 输出结果:
helloworld

关键字

go语言数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。

数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

Go 语言按类别有以下几种数据类型:

类型 描述
布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
派生类型: 包括:指针类型、 数组类型 、 结构化类型(struct) 、 Channel 类型 、函数类型 、切片类型 、接口类型(interface)、Map 类型

数字类型:

类型 描述
uint8 无符号 8 位整型 (0 到 255)
int8 有符号 8 位整型 (-128 到 127)
uint16 无符号 16 位整型 (0 到 65535)
int16 有符号 16 位整型 (-32768 到 32767)
uint32 无符号 32 位整型 (0 到 4294967295)
int32 有符号 32 位整型 (-2147483648 到 2147483647)
uint64 无符号 64 位整型 (0 到 18446744073709551615)
int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
int 与平台架构相关,32位平台:4字节;64位平台:8字节
uint 与平台架构相关,32位平台:4字节;64位平台:8字节
uintptr 与平台架构相关,32位平台:4字节;64位平台:8字节;用来存储任何指针(地址)的值,但它本身是一个整数,不携带任何指针的语义。
byte 1字节,用于存储ASCII表中字符的字符类型 ,底层是uint8,byte是uint8的一个别名
rune 4字节,用于存储多字节字符的类型,比如:中文字符、韩文字符、日文字符等 ,底层是int32,rune是int32的一个别名

浮点类型:

类型 描述
float32 IEEE-754 32位浮点型数
float64 IEEE-754 64位浮点型数
complex64 32 位实数和虚数
complex128 64 位实数和虚数

其中:布尔类型、数字类型、浮点类型、字符串类型是go语言的基本数据类型

go语言变量

go语言中变量需要使用var关键字来定义

在go语言中定义变量的方式有以下几种:

1. 对于局部变量来说:

go 复制代码
// 完整定义+初始化
var name string = "hello"

// 短声明(编译器会自动根据`=`的复制内容类确定变量类型),
// 相当于编译器自动完成了声明+赋值
sex := "man"

// 不完整初始化,编译器会根据赋值内容,自动推导变量的类型
var age = 28

// 仅声明,未赋值,默认值为声明类型的默认值,string类型默认值就是空串; 
var word string

对于局部变量来说,定义出来就必须要使用,不然会报错!

2. 对于全局变量来说:

go 复制代码
// 允许
var global string = "sssssss"
// 允许
var global3 = "aaaaaa"
// 允许
var global2 string

// 对于全局变量的声明不允许使用短声明!!!
global4 :="dddddd"

对于全局变量来说,定义出来可以不使用,编译器不会报错!

  1. 一次性声明多个变量
go 复制代码
	// 显示初始化
	var a, b, c, d int = 1, 2, 3, 4

	// 根据赋值内容自动推导变量类型
	var (
		e = 3
		f = 5
		h = 7
	)

  // 显示初始化
	var (
		sh   int    = 29
		dcdh bool   = true
		cnjd string = "hello"
	)

go语言常量

在go语言中,常量使用const来进行修饰
常量的定义有以下几种方式:

go 复制代码
	// 显示指定类型初始化
	const a int = 10
	const b string = "hello"
	const c bool = false

	// 通赋值内容自动推导
	const (
		d = 3.45
		e = '你'
		f = 's'
	)

对于常量来说不必像变量那样定义了就必须使用,在go语言中无论是全局常量还是局部常量定义了都可以不必使用。

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

  1. 在一个新的const初始化块中,iota会被初始化为0,之后const初始化块中,每声明一个常量,iota就会自动+1,由编译器自动进行维护;
go 复制代码
	const (
		a = iota // 0
		b = iota // 1
		c = iota // 2
		d = iota // 3
	)
	//在新的const块中iota会被重新初始化为0
	const (
		a1 = iota // 0
		b1 = iota // 1
		c1 = iota // 2
		d1 = iota // 3
	)
  1. 在const块中,如果常量没有进行显示的赋值,那么它会沿用前一个有赋值表达式的值
go 复制代码
package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1 沿用a = iota的赋值,也就是: b= iota
            c          //2 沿用a = iota的赋值,也就是: c= iota
            d = "ha"   //独立值
            e          //"ha" ,沿用d= "ha"的赋值,也就是: e="ha"  
            f = 100    //独立值
            g          //100 沿用f=100的赋值,也就是: g=100
            h = iota   //7,恢复计数
            i          //8 沿用h=iota,也就是: i= iota
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

go语言运算符

go语言的运算符与其他语言的运算符大差不差:

算术运算符:

运算符 描述
+ 相加
- 相减
* 相乘
/ 相除
% 取模
++ 后置++
-- 后置- -

关系运算符:

运算符 描述
== 检查两个值是否相等,如果相等返回 True 否则返回 False。
!= 检查两个值是否不相等,如果不相等返回 True 否则返回 False。
> 检查左边值是否大于右边值,如果是返回 True 否则返回 False。
< 检查左边值是否小于右边值,如果是返回 True 否则返回 False。
>= 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
<= 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。

逻辑运算符:

运算符 描述
&& 如果两边的操作数都是 True,则条件 True,否则为 False。
|| 如果两边的操作数有一个 True,则条件 True,否则为 False。
! 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。

位运算符:

运算符 描述
& 按位与;1 &1 =1 ,1 & 0=0, 0&1=0,0&0=0
| 按位或;1|1=1,1|0=1,0|1=1,0|0=0
^ 按位异或;1^1=0,1^0=1,0^1=1,0^0=0
<< 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。
>> 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。

赋值运算符:

运算符 描述
= 简单的赋值运算符,将一个表达式的值赋给一个左值
+= 相加后再赋值
-= 相减后再赋值
*= 相乘后再赋值
/= 相除后再赋值
%= 求余后再赋值
<<= 左移后赋值
>>= 右移后赋值
|= 按位或后赋值
&= 按位与后赋值
^= 按位异或后赋值

指针运算符:

运算符 描述
& 返回变量存储地址
* 指针变量。

go语言条件语句

  1. if语句
go 复制代码
// 语法
if 布尔表达式{
	// to do...
}
  1. if...else语句
go 复制代码
if 布尔表达式{
	//todo....
}else{
	// todo...
}
  1. if语句嵌套
go 复制代码
if 布尔表达式1{
		// todo...
		if 布尔表达式2{
		// tood...
	}
}
  1. elif语句
go 复制代码
if 布尔表达式1{
	//todo...
}else if 布尔表达式2{
	// todo...
}else{
	// todo...
}
  1. switch语句

switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。

switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。

变量 varnum可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。

go 复制代码
// switch 第一种用法
switch varnum{
case var1:
case var2:
case var3:
.....
case var6:
case var7:
default:

}

// 当varnum匹配case var4的时候,case var6也会被执行!
switch varnum{
case var1:
case var2:
case var3:
case var4:
	fallthrough
case var6:
case var7:
default:

}


	//switch 的第二种用法,switch可以不用写需要判定的变量
	var age int
	fmt.Scanf("%d", &age)
	switch {
	case age < 18:
		fmt.Println("未成年")
	case age >= 18 && age < 65:
		fmt.Println("成年人")
	case age >= 65:
		fmt.Println("老年人")
	default:
		fmt.Println("输入有误")
	}
	
	//switch第三种用法,type switch
	//注意想要使用这种类型的switch,var2必须是接口类型,也就是interface{}类型
	var var2 interface{} = age
	switch var2.(type) {
	case int:
		fmt.Println("var2是int类型")
	case string:
		fmt.Println("var2是string类型")
	default:
		fmt.Println("var2是其他类型")
	}

go语言循环语句

在go语言中只有for循环,没有while循环、do while循环;

  1. 标准for循环
go 复制代码
 for init; condition; post {

 }
 
 for i:=0;i<=10;i++{
 	// todo...
 }
  1. 使用for循环仿照while循环
go 复制代码
for 布尔表达式{
	// todo
}

for i<=100{
	sum+=i;
	i++;
}
  1. 死循环
go 复制代码
// 方式1
for true {
	// todo
}
// 方式2
for {
// todo
}
  1. 配合range使用
go 复制代码
//for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
// 1. 遍历map
for key,value:= range map1{
	//todo...
}
//只读key,不读value
for key:=range map1{
	//todo..
}
//只读valuee,不读key
for _,value:=range map1{
// todo...
}

// 2. 遍历数组
for index,val range arr{
	//todo...
}
  1. break语句
    经常用于中断当前 for 循环或跳出 switch 语句
  2. continue语句
    跳过当前循环的剩余语句,然后继续进行下一轮循环。
  3. goto语句
    将控制转移到被标记的语句。
    在go语言中,标记一旦被定义就必须被使用,不然会报错!

go语言函数

语法:

go 复制代码
func function_name( [parameter list] ) [return_types] {
   函数体
}

//eg:
func Add(x,int,y int)(z int){
	return x+y
}

函数定义解析:

func:函数由 func 开始声明

function_name:函数名称,参数列表和返回值类型构成了函数签名。

parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。语法糖:当有多个连续的参数具有相同的类型时,可以将参数的类型声明写在最后一个,eg:

go 复制代码
func show(a string, b int, c int, d bool) {
	fmt.Println(a, b, c, d)
}
// 根据语法糖,可以写成下面这种形式:
// 参数b的类型声明可以和参数c的类型声明合并在一起
func show(a string, b, c int, d bool) {
	fmt.Println(a, b, c, d)
}

return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。

函数的用法

  1. 将函数作为另一个函数的实参
go 复制代码
func test3() {

	getSqurtNum := func(x float64) float64 {
		return math.Sqrt(x)
	}
	fmt.Println(getSqurtNum(92845))
}
  1. 闭包(匿名函数)
    匿名函数是一种没有函数名的函数,通常用于在函数内部定义函数,或者作为函数参数进行传递。
    类似C++的lamda表达式。
go 复制代码
func getSequence() func() int {
	i := 0
	func1 := func() int {
		i++
		return i
	}
	return func1
}
func test3() {

	nextNumber := getSequence()

	fmt.Println(nextNumber()) // 1
	fmt.Println(nextNumber()) // 2
	fmt.Println(nextNumber()) // 3

	newSeq := getSequence()
	fmt.Println(newSeq()) // 1
	fmt.Println(newSeq()) // 2
	fmt.Println(newSeq()) // 3

}
  1. 方法
    Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型 或者结构体类型 的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。语法格式如下:
    类似于其它语言的成员函数
go 复制代码
func (variable_name variable_data_type) function_name() [return_type]{
   /* 函数体*/
}

//eg:
type Student struct {
	name string
	age  int
}

func (s Student) printStudentInfo() {
	fmt.Printf("学生姓名:%s,年龄:%d\n", s.name, s.age)
}

func test4() {
	var s1 Student = Student{age: 20, name: "李四"}
	//输出: 学生姓名:李四,年龄:20
	s1.printStudentInfo()
}
相关推荐
layman05281 小时前
在python中受限于GIL,进程中只允许一个线程处于允许状态,多线程无法充分利用CPU多核
开发语言·python
捧 花1 小时前
Go Web 开发流程
开发语言·后端·golang·restful·web·分层设计
镜花水月linyi1 小时前
1.5w字ReentrantLock 深度解析
java·后端·程序员
bot5556661 小时前
企业微信iPad协议:从接口设计到灰度验证的极简实践
后端
CC.GG1 小时前
【Qt】Qt初识
开发语言·qt
程序员西西2 小时前
Spring Boot3 分页操作全解析:从基础到实战
java·后端·程序员
用户68545375977692 小时前
为什么Python大神都在用with?看完我悟了
后端
mudtools2 小时前
一分钟实现.NET与飞书长连接的WebSocket架构
后端·c#·.net
Mcband2 小时前
【Spring Boot】Interceptor的原理、配置、顺序控制及与Filter的关键区别
java·spring boot·后端