点击名片关注 阿尘blog,一起学习,一起成长
本文主要分享初次学习GO语言的一些注意事项和基础!
1、GO语言的环境准备和第一个程序:
运行单个编译文件,包名必须是main,go语言的包名和java不一致,可以不与目录一样
环境搭建参考文章
goland开发环境搭建及运行第一个go程序HelloWorld_goland运行go项目-CSDN博客
2、go语言的变量
过语言的变量必须声明
如果声明没有被使用,会报错
不带声明格式的变量不能再函数体外使用,因为不带声明格式的函数是局部变量,只能在声明它们的函数或代码块内部使用。这些变量是自动类型推断的,并且只在当前的函数或代码块内有效。
局部变量优先于全局变量
3、函数后的大括号不能换行
在 Go 语言中,函数体的大括号 {}
通常不会紧跟在函数名后面立即换行,而是与函数名在同一行,这是 Go 语言的常见编码风格。这样做有助于提高代码的可读性,使代码看起来更整洁。
func myFunction() {
// 函数体
// ...
}
4、go语言没有三目运算符
三目运算符,也被称为条件运算符,是一种在许多编程语言中常见的运算符,用于根据某个条件的结果选择两个值中的一个。然而,Go语言选择不使用这种运算符,主要是因为Go语言的设计目标之一是保持语法的简洁性和一致性。
5、匿名函数与闭包的关系
匿名函数:
匿名函数是没有名称的函数,也称为闭包函数(Closure Function)。它们可以作为一种值被传递,并且可以引用其外部函数的变量。由于它们没有名称,因此不能独立地调用,但可以作为参数传递给其他函数,或者在需要函数值的地方使用。
闭包:
闭包是一个函数以及与其相关的引用环境的组合。换句话说,闭包是一个函数,它记住了并访问其词法作用域,即使该函数在其原始作用域之外执行。当一个函数引用了其外部作用域的变量时,就形成了一个闭包。闭包可以访问和控制其外部作用域的变量,即使外部函数已经执行完毕。
关系:
在Go语言中,匿名函数是闭包的一种实现方式。当你创建一个匿名函数并引用外部变量时,你就创建了一个闭包。闭包允许函数保留对其词法作用域中变量的引用,并且这些变量在闭包的生命周期内都是有效的。这意味着即使外部函数已经返回,闭包仍然可以访问和修改这些变量。
下面是一个Go语言中匿名函数和闭包的简单示例:
package main
import "fmt"
func main() {
x := 10
// 创建一个匿名函数,并引用外部变量x
add := func(i int) int {
return x + i
}
// 调用匿名函数
fmt.Println(add(5)) // 输出:15
// 修改外部变量x的值
x = 20
// 再次调用匿名函数,闭包仍然可以访问修改后的x值
fmt.Println(add(5)) // 输出:25
}
在上面的示例中,我们定义了一个匿名函数add
,它引用了外部变量x
。由于匿名函数引用了外部变量,因此形成了一个闭包。即使main
函数中的x
值被修改,闭包中的add
函数仍然能够访问和使用修改后的x
值。
总结来说,匿名函数是闭包的一种实现方式,而闭包是通过引用外部变量形成的函数与其相关引用环境的组合。在Go语言中,匿名函数和闭包常用于实现回调函数、高阶函数和函数式编程等概念。
6、注释:
-
单行注释:
-
单行注释以
//
开头,并持续到该行的末尾。 -
它通常用于解释代码的功能、目的或实现细节。
-
示例:
// 这是一个单行注释
多行注释:
-
多行注释以
/*
开头,并以*/
结尾。 -
这种注释方式可以跨越多行,并包含单行注释。
-
注意,多行注释中不允许嵌套使用多行注释,否则编译器会报错。
-
示例:
/* 这是一个多行注释,可以跨越多行 */
7、命名
Go语言中的函数名、变量名、常量名、类型名、语句标号、和包名都必须以一个字母或下划线开头,GO语言严格区分大小
8、关键字
GO语言的关键字有25个
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
此外,还有大约30多个预定义的名字,比如int和true等,主要对应内建的常量、类型和函数。
内建常量: true false iota nil
内建类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
内建函数: make len cap new append copy close delete
complex real imag
panic recover
9 声明
声明语句定义了程序的各种实体对象以及部分或全部的属性。Go语言主要有四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明。
一个Go语言编写的程序对应一个或多个以.go为文件后缀名的源文件。每个源文件中以包的声明语句开始,说明该源文件是属于哪个包。包声明语句之后是import语句导入依赖的其它包,然后是包一级的类型、变量、常量、函数的声明语句,包一级的各种类型的声明语句的顺序无关紧要(译注:函数内部的名字则必须先声明之后才能使用)
9.1 变量的声明
声明变量的表达式一般如下::
`var 变量名字 类型 = 表达式``
类型和= 表达式是可以省略的,类型省略将根据初始化表达式太菜变量的类型,如果初始化表达式省略,将默认用对应零值来初始化,避免了报错
GO语言数据类型,默认零值
数据类型 | 默认零值 | 解释 |
---|---|---|
bool | false | 布尔类型 |
int | 0 | 整数类型,包含(int8,int16,int32,int64) |
float | 0.0 | 浮点数类型(float32、float64) |
complex | (0+0i) | 复数类型(complex64、complex128),默认包含实部和虚部 |
string | “” | 字符串类型,表示文本数据 |
array | 数组元素类型的零值 | |
slice | nil | 切片类型[]T动态数组 |
pointer | nil | 指针类型 |
map | nil | |
struct | 结构体中每个字段的零值 | |
interface | nil | 接口类型 |
function | nil | 函数类型 |
channel | nil |
GO可以在个声明语句中同事声明一组变量,或者在一个表达式中声明并初始化一组变量
var i, j, k int // int, int, int
var b, f, s = true, 2.3, "four" // bool, float64, string
简短声明
`name := 表达式``
简短声明注意事项:
只能在函数内部使用
不能提供数据类型
声明同时初始化
9.2 变量赋值
直接赋值
var a int
a = 10
声明同时赋值
var b string = "hello"
多重赋值
var d, e int
d, e = 30, 40
简短赋值
c := 20
9.3 匿名变量
匿名变量用__来表示,叫做占位符 或者空标识符,主要用于函数返回值、变量赋值、结构体中的成员等,匿名变量省略了变量名,避免变量名的定义和石笋,减少代码量和命名冲突的可能,匿名变量不分配内存,不会占用内存
使用场景
func test() (int, string) {
return 10, "hello"
}
x, _ := test()
上面我们用匿名变量来处理忽略不要的变量
type Person struct {
Name string
Age int
}
type Student struct {
Person
Score float64
}
var s Student
s.Name = "Tom"
s.Age = 18
s.Score = 90.5
在上面的代码中,结构体Student
中有一个匿名字段Person
,可以通过s.Name
和s.Age
来访问Person
结构体中的字段。
需要注意的是,在使用匿名变量时,虽然可以省略变量名,但是需要保留变量类型。否则会出现编译错误。
9.4 常量
在Go语言中,常量的定义使用关键字const
,常量名一般使用大写字母,多个单词之间使用下划线分隔。常量的值可以是数字、字符串、布尔值等。
const Pi = 3.14159
const Greeting = "Hello, World!"
const MaxInt32 = 1<<31 - 1
const Debug = false
常量还可以使用iota
来进行自增,它用于枚举、位运算等场景。iota
的初始值为0,每出现一次iota
,它的值就自增1。下面是一个枚举的例子:
package main
import "fmt"
const (
Monday = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
func main() {
fmt.Println(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
}
//0 1 2 3 4 5 6
10 数据类型
基本类型 | 说明 |
---|---|
bool | 布尔型,值为true或false |
uint8 | 8位无符号整型,取值范围为0到255 |
uint16 | 16位无符号整型,取值范围为0到65535 |
uint32 | 32位无符号整型,取值范围为0到4294967295 |
uint64 | 64位无符号整型,取值范围为0到18446744073709551615 |
int8 | 8位有符号整型,取值范围为-128到127 |
int16 | 16位有符号整型,取值范围为-32768到32767 |
int32 | 32位有符号整型,取值范围为-2147483648到2147483647 |
int64 | 64位有符号整型,取值范围为-9223372036854775808到9223372036854775807 |
float32 | 32位浮点型,可以表示小数,精度为7位小数 |
float64 | 64位浮点型,可以表示小数,精度为15位小数 |
byte | 8位无符号整型,与uint8相同 |
rune | 32位有符号整型,表示一个Unicode码点 |
uintptr | 无符号整型,用于存放一个指针的地址 |
复合类型 | 说明 |
---|---|
string | 字符串类型,由一串Unicode码点组成 |
array | 数组类型,元素类型相同,长度固定 |
slice | 切片类型,可以动态增长或缩小长度 |
map | 映射类型,键值对类型 |
struct | 结构体类型,由若干个字段组成,每个字段可以是任意类型 |
interface | 接口类型,可以包含任意类型的值 |
channel | 通道类型,用于在多个goroutine之间传递数据 |
go语言的格式化输出 Go语言中的格式化输出是通过fmt包实现的,它支持的格式化动词与C语言中的printf函数类似,但也有一些不同之处。
下面是几个常用的格式化动词及其含义:
%d:将整数格式化为十进制整数。%f:将浮点数格式化为十进制浮点数。%e:将浮点数格式化为科学计数法表示。%s:将字符串格式化为字符串。%v:将值的默认格式表示为字符串。除了动词之外,还可以使用一些修饰符来控制输出格式,如:
%5d:将整数格式化为长度为5的十进制整数。%6.2f:将浮点数格式化为长度为6,保留2位小数的十进制浮点数。下面是一些例子,展示了如何使用格式化输出:
package main
import "fmt"
func main() {
x := 123
y := 3.14159
s := "hello"
fmt.Printf("x=%d, y=%f, s=%s\n", x, y, s)
fmt.Printf("x=%5d, y=%6.2f, s=%s\n", x, y, s)
}
x=123, y=3.141590, s=hello
x= 123, y= 3.14, s=hello
在上面的例子中,fmt.Printf函数使用格式化字符串来格式化输出。在格式化字符串中,%d表示整数,%f表示浮点数,%s表示字符串。使用%d和%f时,需要将要输出的值作为参数传递给fmt.Printf函数,使用%s时,直接将要输出的字符串作为参数传递即可。
值得注意的是,使用fmt.Printf函数时,输出格式的字符串和参数列表中的值一一对应,如果不匹配会导致运行时错误。此外,fmt.Printf函数还有其他一些格式化输出相关的函数,如fmt.Sprintf、fmt.Fprintf等,使用方式与fmt.Printf类似。
特殊类型的定义示例
package main
import "fmt"
func main() {
// 定义一个包含5个整数的数组
var numbers [5]int
// 初始化数组
numbers = [5]int{1, 2, 3, 4, 5}
// 访问数组元素
fmt.Println(numbers[2]) // 输出:3
// 修改数组元素
numbers[2] = 20
fmt.Println(numbers) // 输出:[1 2 20 4 5]
}
package main
import "fmt"
func main() {
// 定义一个初始切片
numbers := []int{1, 2, 3, 4, 5}
// 访问切片元素
fmt.Println(numbers[2]) // 输出:3
// 修改切片元素
numbers[2] = 20
fmt.Println(numbers) // 输出:[1 2 20 4 5]
// 切片增长
numbers = append(numbers, 6)
fmt.Println(numbers) // 输出:[1 2 20 4 5 6]
}
package main
import "fmt"
// 定义一个结构体类型
type Person struct {
Name string
Age int
City string
}
func main() {
// 创建一个Person类型的变量
p := Person{
Name: "Alice",
Age: 30,
City: "New York",
}
// 访问结构体字段
fmt.Println(p.Name) // 输出:Alice
fmt.Println(p.Age) // 输出:30
fmt.Println(p.City) // 输出:New York
}
package main
import "fmt"
func main() {
// 定义一个映射
person := make(map[string]int)
// 向映射中添加键值对
person["Alice"] = 30
person["Bob"] = 25
// 访问映射中的值
fmt.Println(person["Alice"]) // 输出:30
// 遍历映射
for name, age := range person {
fmt.Printf("%s is %d years old\n", name, age)
}
}
package main
import "fmt"
func main() {
// 创建一个通道
ch := make(chan string)
// 启动一个goroutine,向通道中发送数据
go func() {
ch <- "Hello, Channel!"
}()
// 从通道中接收数据
msg := <-ch
// 打印接收到的数据
fmt.Println(msg) // 输出:Hello, Channel!
}
package main
import "fmt"
func main() {
// 定义一个整数变量
var num int = 42
// 获取num的内存地址,并创建一个指向num的指针变量p
p := &num
// 使用*操作符来访问指针指向的值
fmt.Println(*p) // 输出:42
// 修改指针指向的值
*p = 100
// 再次访问num的值,发现它已经被修改
fmt.Println(num) // 输出:100
// 指针也可以指向其他类型的变量
var str string = "Hello, Pointer!"
strPtr := &str
fmt.Println(*strPtr) // 输出:Hello, Pointer!
// 判断指针是否为空
var nilPtr *int
fmt.Println(nilPtr) // 输出:nil
// 使用new函数分配内存并返回指针
newInt := new(int)
*newInt = 5
fmt.Println(*newInt) // 输出:5
}
如果本文有地方遗漏错误,欢迎大家一起交流,仅供参考!
扫描二维码关注阿尘blog,一起交流学习