1. 介绍
- 欢迎来到Go语言的世界!作为一门新兴的编程语言,Go语言具有高效、简洁、安全等特点,逐渐受到了越来越多开发者的关注和喜爱。
- 在本文中,我们将一起学习了解Go语言的基础语法。
2. 基础语法
2.1 写一个Hello World
让我们用最简单的方式先进入Go语言的世界——写一个Hello World。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
其中,Keyword package 声明所在模块名称,Keyword import 引入必要的包,func main 是程序的入口函数,通过fmt包中的Println函数,输出"Hello World!" 的字符串信息。
2.2 变量的声明和定义
Go语言是静态类型语言,使用 var 关键字进行变量声明时需要指定数据类型。同时也可以使用下面这种简化的方式:
var message string = "Hello World!"
var a, b, c int = 1, 2, 3
s := "Go语言入门"
在第三行代码中,使用 := 代替了 var关键字和数据类型定义操作。这是因为 Go 语言的编译器能够通过变量字面值自动判断出变量的类型。
注意,在Go语言中,已声明但未使用的变量会引发编译错误。
2.3 if-else
在Go语言中,if 和 else 的语法与其他语言差不多。if 后跟条件表达式,然后是代码块。else 被用来指定与条件不匹配时执行的代码块。
if age >= 18 {
fmt.Println("成年人")
} else {
fmt.Println("未成年人")
}
2.4 for循环
Go 语言中成对出现的大括号 { } 必须与语句在同一行上。Go 语言中没有 while 循环,在循环语句中使用 for ,可以有单一的条件表达式,也可以有三个表达式组成的条件表达式。
for i := 0; i < 10; i++ {
fmt.Printf("%d ", i)
}
其中,i := 0 是初始化语句,它定义并初始化了一个变量 i;i < 10 是条件表达式,它会在每次循环开始时测试条件 true or false 是否满足;i++ 是后置语句。每次循环结束后都会执行一次后置语句。
2.5 switch
在 Go 语言中,switch 语句类似于 if 语句,但是适用于多个条件判断场景。
switch grade {
case "A":
fmt.Println("优秀")
case "B":
fmt.Println("良好")
case "C":
fmt.Println("及格")
default:
fmt.Println("不及格")
}
2.6 数组
数组是指一组固定长度且类型相同的元素排列所组成的数据结构。在Go语言中,数组通过 [n]T 定义,其中 n 表示数组的长度,T 表示数组元素的类型。
var a [5]int
a[2] = 3
fmt.Println(a)
2.7 切片
切片(slice)是一种动态数组,在很多方面比传统的数组更灵活、更强大;同时也支持类似于数组的索引和遍历操作。
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println(len(s))
2.8 map
map 是一种键值对(key-value)数据结构,在需要快速查找特定键值时极其实用,和其它语言中的字典(dictionary)、哈希表(hash)、关联数组等类似。
ages := make(map[string]int)
ages["Alice"] = 31
ages["Bob"] = 20
ages["Charlie"] = 25
fmt.Println(ages["Bob"])
2.9 range
range 关键字用来实现for循环中针对数组、切片、字符串等的迭代操作。配合 for 循环可以形成迭代器遍历循环。
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
2.10 函数
Go语言的函数定义格式如下:
func functionName(parameter1 type, parameter2 type) returnType {
// function body
}
其中,functionName 指定函数名,可以包含一个或多个输入参数和一个返回值类型。函数体内的逻辑是需要执行的操作。
2.11 指针
指针是一种特殊的变量,用于存储另一个变量的内存地址。Go语言的指针类型使用*来表示,通过&运算符获取一个变量的内存地址。对于指针类型变量,可以使用*运算符来获取其指向的变量的值。
// 定义指针变量
var a int = 10
var p *int = &a
// 获取指针指向的变量的值
fmt.Println(*p) // 输出为 10
// 修改指针指向的变量的值
*p = 20
fmt.Println(a) // 输出为 20
需要注意的是,Go语言中没有指针运算和指针比较等操作,以确保程序的安全性。
在实际编程过程中,指针通常用于传递函数参数、动态内存分配等场景。
2.12 结构体
结构体是一种复合类型,可以将多个不同类型的数据组合成一个有意义的整体。使用type和struct关键字进行定义,其中可包含不同类型的字段,每个字段都有自己的名称和类型。
// 定义一个结构体类型
type person struct {
name string
age int
gender string
}
// 创建一个结构体实例
p := person{"Alice", 18, "female"}
// 访问结构体成员
fmt.Println(p.name) // 输出为 Alice
可以使用.(点)来访问结构体中的字段。
2.13 结构体方法
与其他面向对象编程语言类似,Go语言也支持在结构体类型上定义方法。方法是与特定类型相关联的函数,使用func关键字和接收者(receiver)进行定义,而接收者就是该方法作用的结构体实例。
// 在 person 类型上定义方法
func (p *person) sayHello() {
fmt.Printf("Hi, my name is %s, I'm %d years old.\n", p.name, p.age)
}
// 调用结构体方法
p.sayHello() // 输出为 "Hi, my name is Alice, I'm 18 years old."
需要注意的是,方法接收者必须是指针类型或者值类型。
2.14 错误处理
Go语言中的错误处理非常灵活,通过返回一个error类型的值来表示某个操作是否出错。如果没有出错,则返回nil。可以使用if-else语句或者panic/recover机制来捕获和处理异常情况。
// 自定义错误类型
type MyError struct {
code int
message string
}
func (err MyError) Error() string {
return fmt.Sprintf("error code: %d, message: %s", err.code, err.message)
}
// 使用自定义错误类型进行错误处理
func divide(a, b int) (int, error) {
if b == 0 {
return 0, MyError{1001, "division by zero"}
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
2.15 字符串操作
Go语言的字符串是不可变的,所以每个字符串都应被视为只读操作方式,任何修改字符串数据的尝试都将导致编译时错误。
要完成字符串拼接,在Go中可以使用+运算符或strings.Join()方法。
// 字符串拼接
str1 := "hello"
str2 := "world"
str3 := str1 + " " + str2
// 或者
strList := []string{"hello", "world"}
str4 := strings.Join(strList, " ")
截取字符串可以使用切片操作。需要注意的是,子串左边界从0开始,右边界从1开始,都包含在了结果字符串内。
// 截取字符串
str := "hello world"
substr := str[0:5] // "hello"
对于其他常见的字符串处理需求,Go语言也提供了相应的函数,例如:
// 替换字符串中的某个子串
newStr := strings.Replace(oldStr, oldSubstr, newSubstr, -1) // -1表示全部替换
// 大小写转换
upperStr := strings.ToUpper(str)
lowerStr := strings.ToLower(str)
// 判断字符串是否以某个前缀或后缀开头或结尾
hasPrefix := strings.HasPrefix(str, prefix)
hasSuffix := strings.HasSuffix(str, suffix)
// 分割字符串
subStrList := strings.Split(str, sep)
2.16 字符串格式化
Go语言的fmt包提供了非常灵活的字符串格式化功能。其中最常用的方式便是Printf()函数,可以打印各种格式标识符代表的值(例如:%d表示整数,%f表示浮点数,%s表示字符串)。
// 字符串格式化并输出到标准输出
fmt.Printf("str1: %s, str2: %s\n", str1, str2)
// 将格式化字符串输出成字符串
formattedStr := fmt.Sprintf("name: %s, age: %d", name, age)
2.17 JSON处理
Go语言内置了对JSON格式的支持,可以通过encoding/json包实现JSON格式数据和Go语言结构体之间的相互转化。
在将Go语言中的变量转化为JSON格式时,需要使用json.Marshal()函数。反过来,JSON数据可以转换为Go语言结构体类型,截止当前日期,也可以使用json.Unmarshal()函数。
例如,下面的代码演示了如何将一个结构体转换为JSON字符串,并且将这个字符串解析为一个新的结构体:
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Height float64 `json:"height"`
}
func main() {
p1 := Person{
Name: "Alice",
Age: 30,
Height: 170.5,
}
// 将结构体转为JSON字符串
jsonData, err := json.Marshal(p1)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("JSON data:", string(jsonData))
// 将JSON字符串解析为结构体
var p2 Person
if err := json.Unmarshal(jsonData, &p2); err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", p2)
}
2.18 时间处理
Go语言的time包提供了各种用于时间处理和格式化的函数,使用这些函数可以获取当前时间、计算时间间隔等。
// 获取当前时间
now := time.Now()
// 时间转换成字符串
fmt.Println(now.Format("2006-01-02 15:04:05"))
// 字符串转换成时间
t, err := time.Parse("2006-01-02 15:04:05", "2023-05-12 21:27:00")
if err != nil {
fmt.Println(err)
return
}
// 计算两个时间间隔
duration := now.Sub(t)
fmt.Println(duration.Hours()) // 输出相差小时数
2.19 数字解析
Go语言提供了很多强大的数字解析功能,strconv包实现了基础类型和其它数据类型之间的相互转化,例如将字符串解析成整型、浮点型等。
import (
"fmt"
"strconv"
)
func main() {
str := "100"
// 将字符串转为int类型
i, err := strconv.Atoi(str)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%d\n", i)
// 将字符串转为float64类型
f, err := strconv.ParseFloat(str, 64)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%f\n", f)
}
2.20 进程信息
Go语言的os包提供了访问进程相关信息的函数。可以获取进程ID,获取命令行参数、环境变量等信息。
下面的示例代码展示如何使用os包输出运行程序时传入的所有命令行参数:
import (
"fmt"
"os"
)
func main() {
args := os.Args[1:]
for _, arg := range args {
fmt.Println(arg)
}
}
3. 总结
- 总的来说,虽然Go语言在语法上与其他编程语言有所不同,但是通过使用它独特的类型系统、并发机制、内存管理和错误处理等特性,可以编写出更加安全、高效的程序,适合用于分布式系统、网络服务和大规模数据处理等领域。
- 呼~ 码字不易,对你有用的话可以点赞和收藏。