加入青训营以后又可以学习一门语言啦!我们和以前一样,从Hello, World开始吧!
要一辈子golang哦
1.创建第一个 Go 程序
创建一个名为 hello.go 的文件,并编写以下代码:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
下面,我们将来介绍其中每一个语句的作用以及基础语法和常用特性
2. 运行 Go 程序
在终端中导航到 hello.go 文件所在的目录,然后运行以下命令:
go run hello.go
它会先编译代码,然后立即运行生成的可执行文件。这个命令适用于快速测试和运行 Go 程序,但不会生成一个独立的可执行文件。
如果你想要单独编译代码并生成可执行文件,可以使用以下命令:
go build hello.go
这会在当前目录下生成一个可执行的.exe文件
3. 基础语法
一般变量声明:
-
显式声明: 使用
var关键字显式声明变量,可以指定变量类型,也可以省略类型让编译器自动推断。var a int = 1 var b = 20 // 类型推断 -
简短声明: 使用
:=进行简短声明,只能在函数内部使用,编译器会自动推断变量类型。c := 30 -
多变量声明: 可以同时声明多个变量。
var x, y, z int var i, j = 1, 2 k, l := 3, 4 -
零值初始化: 未显式初始化的变量会被赋予其类型的零值。
var s string //空字符串 "" var n int // 0 var f float6` // 0.0 var b bool // false -
匿名变量: 使用
_作为匿名变量,可以忽略不需要的返回值。_, err := someFunction() -
常量声明: 使用
const关键字声明常量,常量的值在编译时确定,不能被修改。const Pi = 3.14
函数声明与特点:
-
基本语法: 使用
func关键字声明函数,函数名后跟参数列表和返回值类型。func functionName(parameterName type) returnType {// 函数体} -
多返回值: Go 语言支持函数返回多个值,这在处理错误时非常有用。
func swap(x, y string) (string, string) {
return y, x
}//交换两个字符串的内容
func main() {
a, b := "hello", "world"
fmt.Println("Before swap:", a, b)
a, b = swap(a, b)
fmt.Println("After swap:", a, b)
}
其中(string, string)代表返回值的类型,所以尤其要注意return的顺序,接收时可使用如案例所示方式
- 命名返回值: 可以为返回值命名,这样在函数体内可以直接使用这些变量,并且在
return语句中可以省略返回值。
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return //返回的值为x,y
}
- 可变参数: 使用
...语法表示可变参数,函数可以接受不定数量的参数。
func printNumbers(numbers ...int) {
for _, number := range numbers {
fmt.Println(number)
}
}
- 匿名函数和闭包: 支持匿名函数和闭包,可以在函数内部定义和调用匿名函数。
func main() {
add := func(a, b int) int {
return a + b
}
fmt.Println(add(3, 4))
}
}
控制结构
Go中控制结构与c/c++,Java的主要区别是无需()
// if 语句
if x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than or equal to 10"
}
// for 循环
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// switch 语句
switch day {
case "Monday":
fmt.Println("Start of the week")
case "Friday":
fmt.Println("End of the week")
default:
fmt.Println("Midweek")
}
数组的声明特点
-
固定长度: 数组的长度在声明时就确定,且不能改变。
var arr [5]int -
默认值: 数组元素在声明时会被初始化为其类型的零值。
-
自动推断长度: 使用
...让编译器自动推断数组长度。arr := [...]int{1, 2, 3}
切片的特点
-
动态长度: 切片的长度是动态的,可以根据需要增长或缩减。
var slice []int -
引用类型: 切片是引用类型,指向底层数组的一部分。
arr := [5]int{1, 2, 3, 4, 5} slice := arr[1:4] // [2, 3, 4] -
内置函数: 使用
len获取切片长度,使用cap获取切片容量。slice := []int{1, 2, 3, 4, 5} fmt.Println(len(slice)) // 5 fmt.Println(cap(slice)) // 5 -
切片操作: 可以对切片进行切片操作,生成新的切片。
slice := []int{1, 2, 3, 4, 5} newSlice := slice[1:3] // [2, 3] -
追加元素: 使用
append函数向切片追加元素。slice := []int{1, 2, 3} slice = append(slice, 4, 5) // [1, 2, 3, 4, 5]
示例代码
package main
import "fmt"
func main() {
// 数组示例
var arr [5]int
arr = [5]int{1, 2, 3, 4, 5}
fmt.Println("数组:", arr)
// 切片示例
slice := []int{1, 2, 3}
fmt.Println("切片:", slice)
slice = append(slice, 4, 5)
fmt.Println("追加元素后的切片:", slice)
newSlice := slice[1:4]
fmt.Println("切片操作后的新切片:", newSlice)
}
Map 的特点
-
键值对存储: Map 是一种无序的键值对集合,键和值的类型在声明时必须指定。
var m map[string]int -
动态大小: Map 的大小是动态的,可以根据需要自动扩展。
-
零值为 nil: 未初始化的 Map 的零值是
nil,不能直接存取值,需要使用make函数初始化。var m map[string]int fmt.Println(m == nil) // true -
初始化: 使用
make函数初始化 Map。m := make(map[string]int) -
字面量初始化: 可以使用字面量初始化 Map。
m := map[string]int{"one": 1, "two": 2} -
添加和更新元素: 使用键访问 Map,可以添加或更新元素。
m := make(map[string]int) m["one"] = 1 m["two"] = 2 -
删除元素: 使用
delete函数删除 Map 中的元素。delete(m, "one") -
检查键是否存在: 通过双赋值检测键是否存在。
value, ok := m["one"]
if ok {
fmt.Println("Key exists with value:", value)
} else {
fmt.Println("Key does not exist")
}
- 遍历 Map: 使用
for range循环遍历 Map。
for key, value := range m {
fmt.Println(key, value)
}
- 并发访问: Map 不是线程安全的,在并发访问时需要使用同步机制如
sync.Mutex或sync.RWMutex。
示例代码
package main
import "fmt"
func main() {
// 初始化 Map
m := make(map[string]int)
// 添加元素
m["one"] = 1
m["two"] = 2
// 更新元素
m["two"] = 22
// 检查键是否存在
value, ok := m["one"]
if ok {
fmt.Println("Key 'one' exists with value:", value)
} else {
fmt.Println("Key 'one' does not exist")
}
// 删除元素
delete(m, "one")
// 遍历 Map
for key, value := range m {
fmt.Println(key, value)
}
}
结构体
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
fmt.Println(p.Name)
并发编程
Go 语言内置对并发的支持,使用 goroutine 和 channel 实现并发编程。
// 启动一个 goroutine
go func() {
fmt.Println("Hello from goroutine")
}()
// 使用 channel 进行通信
ch := make(chan int)
go func() {
ch <- 42
}()
fmt.Println(<-ch)
包管理
使用 go get 命令来获取和管理外部包。例如:
go get github.com/gorilla/mux
单元测试
Go 语言内置了测试框架,使用 testing 包编写测试。
package main
import "testing"
func TestAdd(t *testing.T) {
result := add(2, 3)
if result != 5 {
t.Errorf("Expected 5, got %d", result)
}
}
通过以上内容,你已经掌握了 Go 语言的基础语法和常用特性(不再只是hello,world了)。继续深入学习和实践,你将能够更好地使用 Go 语言进行开发。
最后,由于本人最近也在学习Java语言,所以列举了上文中与Java不同的点
变量声明的不同
Go:
- Go 语言支持显式声明和类型推断,使用
var关键字或简短声明:=。 - 未初始化的变量会被赋予零值。
Java:
- Java 语言需要显式声明变量类型,使用
类型 变量名的形式。 - 未初始化的变量不能使用,编译时会报错。
结构控制的不同
条件语句:
Go:
if语句不需要括号,但代码块必须用大括号{}包围。- 支持在
if语句中声明变量。
Java:
if语句需要括号()包围条件表达式,代码块用大括号{}包围。- 不支持在
if语句中声明变量。
循环语句:
Go:
- 只有
for一种循环结构,可以用来实现传统的for循环、while循环和无限循环。 for语句的条件部分不需要括号。
Java:
- 支持
for、while和do-while三种循环结构。 for和while语句的条件部分需要括号。
函数声明的不同
Go:
- 使用
func关键字声明函数。 - 参数类型和返回类型在参数名之后指定。
- 支持多返回值。
- 支持命名返回值。
- 支持匿名函数和闭包。
Java:
- 使用
返回类型 函数名的形式声明函数。 - 参数类型在参数名之前指定。
- 不支持多返回值,但可以使用对象或数组返回多个值。
- 不支持命名返回值。
- 支持匿名类和 lambda 表达式
由此可见Go与Java的区别还是挺大的,但我们万能的程序员会用不同的语言写出(同样的hello,world)不同的功能。语言就像跑鞋,都能走在路上,但雪地靴适合御寒,篮球鞋有更强的防侧翻,每个语言都有其优势区间,而我们要做的就是让语言在最适合自己的位置上发光发热。