【Go-2】基本语法与数据类型

基本语法与数据类型

Go语言作为一种静态类型、编译型语言,拥有简洁且高效的语法结构。本章将深入介绍Go的基本语法和数据类型,帮助你建立扎实的编程基础。

2.1 第一个 Go 程序

编写第一个Go程序是学习任何编程语言的传统步骤。通过一个简单的"Hello, World!"程序,你将了解Go程序的基本结构和运行方式。

main 函数

每个Go程序的执行都从main包的main函数开始。main函数是程序的入口点,定义了程序启动时执行的代码。

示例:

go 复制代码
package main

func main() {
    // 程序入口
}
  • package main: 声明当前文件属于main包。main包是可执行程序的入口包。
  • func main(): 定义main函数,这是程序的起始点。
fmt.Println() 输出

fmt包是Go的标准输入输出包,提供了格式化的I/O函数。fmt.Println()用于在控制台输出文本并换行。

完整的"Hello, World!"程序:

go 复制代码
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

解释:

  • import "fmt": 导入fmt包,以便使用其提供的函数。
  • fmt.Println("Hello, World!"): 输出字符串"Hello, World!"到控制台,并换行。

运行程序:

  1. 保存文件为hello.go

  2. 在终端中导航到文件所在目录。

  3. 执行命令:

    复制代码
    go run hello.go
  4. 输出:

    复制代码
    Hello, World!

编译并运行:

  1. 编译程序:

    复制代码
    go build hello.go

    这将生成一个可执行文件

    复制代码
    hello

    (在Windows上为

    复制代码
    hello.exe

    )。

  2. 运行可执行文件:

    复制代码
    ./hello
  3. 输出:

    复制代码
    Hello, World!

2.2 变量与常量

变量和常量是编程语言中存储和管理数据的基本单元。Go语言提供了多种方式来声明和使用变量和常量。

声明变量

在Go中,变量使用var关键字声明,后跟变量名和类型。

示例:

go 复制代码
var age int
age = 30

var name string
name = "Alice"

也可以在声明时赋值:

go 复制代码
var age int = 30
var name string = "Alice"

Go支持类型推断,即编译器可以根据赋值自动推断变量类型:

go 复制代码
var age = 30          // age为int
var name = "Alice"    // name为string
短变量声明

在函数内部,可以使用短变量声明语法:=来声明并初始化变量,而无需显式指定类型。

示例:

go 复制代码
age := 30
name := "Alice"
isStudent := true

等同于:

go 复制代码
var age int = 30
var name string = "Alice"
var isStudent bool = true
常量与枚举

常量使用const关键字声明,其值在编译时确定,且不可修改。

示例:

go 复制代码
const Pi = 3.14159
const Greeting = "Hello, World!"

Go不直接支持枚举类型,但可以使用常量组合iota来模拟枚举。

示例:

go 复制代码
const (
    Sunday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)

解释:

  • iota是Go的一个预声明标识符,表示常量组中的索引,从0开始。
  • 上述代码定义了一组代表星期的常量,分别为0到6。

使用枚举模拟:

go 复制代码
package main

import "fmt"

const (
    Red = iota
    Green
    Blue
)

func main() {
    fmt.Println(Red)    // 输出: 0
    fmt.Println(Green)  // 输出: 1
    fmt.Println(Blue)   // 输出: 2
}

2.3 数据类型

Go语言提供了多种数据类型,分为基本类型和复合类型。掌握这些数据类型是编写有效Go程序的基础。

基本类型
整型

Go支持多种整型,包括有符号和无符号类型,以及不同位数的类型。

  • 有符号整型:int8, int16, int32, int64, int
  • 无符号整型:uint8, uint16, uint32, uint64, uint
    示例:
go 复制代码
var a int = 10
var b int64 = 10000000000
var c uint = 20
var d uint8 = 255
浮点型

Go支持float32float64两种浮点类型。

示例:

go 复制代码
var pi float32 = 3.14
var e float64 = 2.718281828459045
字符串

字符串是由字符组成的序列,使用双引号"或反引号```包裹。

示例:

go 复制代码
var greeting string = "Hello, World!"
var multiline string = `This is a
multiline string.`

字符串是不可变的,无法直接修改单个字符。

布尔型

布尔类型表示真或假,使用bool类型。

示例:

go 复制代码
var isGoFun bool = true
var isStudent bool = false
复合类型

复合类型是由多个基本类型组成的类型,包括数组、切片、Map、结构体和指针。

数组

数组是具有固定大小和相同类型元素的有序集合。

声明和初始化:

go 复制代码
var arr [5]int
arr[0] = 10
arr[1] = 20

// 声明并初始化
var arr2 = [3]string{"apple", "banana", "cherry"}

// 使用省略长度
arr3 := [...]float64{1.1, 2.2, 3.3}

遍历数组:

go 复制代码
for i, v := range arr2 {
    fmt.Printf("Index: %d, Value: %s\n", i, v)
}
切片

切片是基于数组的动态数据结构,比数组更灵活和强大。切片的长度和容量可以动态变化。

声明和初始化:

go 复制代码
// 空切片
var s []int

// 使用make函数
s1 := make([]int, 5) // 长度为5,元素初始化为0
s2 := make([]int, 3, 10) // 长度为3,容量为10

// 字面量初始化
s3 := []string{"Go", "Python", "Java"}

添加元素:

go 复制代码
s4 := []int{1, 2, 3}
s4 = append(s4, 4, 5)

切片截取:

go 复制代码
s5 := []int{1, 2, 3, 4, 5}
sub := s5[1:3] // 包含索引1和2,不包含3
fmt.Println(sub) // 输出: [2 3]

切片的底层原理: 切片由指向数组的指针、长度和容量组成。切片的容量表示从切片的起始位置到底层数组末尾的元素数量。

Map

Map是键值对的无序集合,键和值可以是不同的类型。Map在Go中作为内置数据类型提供,类似于Python的字典或Java的HashMap。

声明和初始化:

go 复制代码
// 声明为空Map
var m map[string]int

// 使用make初始化
m = make(map[string]int)

// 声明并初始化
m1 := map[string]int{
    "apple":  5,
    "banana": 3,
}

// 使用简短声明
m2 := make(map[string]string)

添加和访问元素:

go 复制代码
m["orange"] = 7
value := m["apple"]
fmt.Println("apple:", value)

删除元素:

go 复制代码
delete(m, "banana")

检查键是否存在:

go 复制代码
value, exists := m["banana"]
if exists {
    fmt.Println("banana exists with value:", value)
} else {
    fmt.Println("banana does not exist")
}

遍历Map:

go 复制代码
for key, value := range m {
    fmt.Printf("Key: %s, Value: %d\n", key, value)
}
结构体

结构体是由多个字段组成的复合数据类型,可以包含不同类型的数据。

定义和使用结构体:

go 复制代码
type Person struct {
    Name string
    Age  int
}

func main() {
    var p Person
    p.Name = "Alice"
    p.Age = 30

    // 使用字面量初始化
    p2 := Person{Name: "Bob", Age: 25}

    fmt.Println(p)
    fmt.Println(p2)
}

嵌套结构体:

go 复制代码
type Address struct {
    City    string
    ZipCode string
}

type Employee struct {
    Person
    Address
    Position string
}

func main() {
    e := Employee{
        Person:   Person{Name: "Charlie", Age: 28},
        Address:  Address{City: "New York", ZipCode: "10001"},
        Position: "Developer",
    }

    fmt.Println(e)
    fmt.Println("City:", e.Address.City)
}

方法与结构体:

Go支持为结构体类型定义方法。

go 复制代码
type Rectangle struct {
    Width, Height float64
}

// 方法接收者为指针类型
func (r *Rectangle) Area() float64 {
    return r.Width * r.Height
}

func main() {
    rect := Rectangle{Width: 10, Height: 5}
    fmt.Println("Area:", rect.Area())
}
指针

指针是存储变量内存地址的变量。Go中使用指针可以提高程序的性能,避免大量数据的复制。

声明和使用指针:

go 复制代码
func main() {
    var a int = 10
    var p *int = &a // p指向a的地址

    fmt.Println("a:", a)       // 输出: a: 10
    fmt.Println("p:", p)       // 输出: p: 地址值
    fmt.Println("*p:", *p)     // 输出: *p: 10

    *p = 20 // 通过指针修改a的值
    fmt.Println("a after:", a) // 输出: a after: 20
}

指针与函数:

使用指针作为函数参数,可以在函数中修改传入的变量。

go 复制代码
func increment(n *int) {
    *n += 1
}

func main() {
    a := 5
    increment(&a)
    fmt.Println("a after increment:", a) // 输出: a after increment: 6
}

2.4 类型转换

在Go中,不同类型之间的转换需要显式进行,称为类型转换。Go不支持隐式类型转换,以确保类型安全。

语法:

go 复制代码
var x int = 10
var y float64 = float64(x)

示例:

go 复制代码
package main

import "fmt"

func main() {
    // 整型与浮点型转换
    var a int = 5
    var b float64 = float64(a)
    var c int = int(b) // 会截断小数部分

    fmt.Println(a, b, c) // 输出: 5 5.0 5

    // 字符串与字节切片转换
    str := "Hello"
    bytes := []byte(str)
    str2 := string(bytes)

    fmt.Println(str, bytes, str2) // 输出: Hello [72 101 108 108 111] Hello

    // 类型之间的转换示例:int到string(需要转换为字符)
    num := 65
    char := string(num)
    fmt.Println(char) // 输出: 'A'
}

注意事项:

  • 只能在兼容类型之间转换,如整数类型之间、浮点类型之间。
  • 字符串与字节切片之间的转换需要使用[]bytestring类型转换。
  • 类型转换可能导致数据丢失,如将float64转换为int会截断小数部分。

更多示例:

go 复制代码
// 将int转换为float64
var i int = 42
var f float64 = float64(i)
fmt.Println(f) // 输出: 42

// 将float64转换为int
var j float64 = 3.14
var k int = int(j)
fmt.Println(k) // 输出: 3

// 将string转换为[]rune
str := "你好"
runes := []rune(str)
fmt.Println(runes) // 输出: [20320 22909]

// 将[]rune转换为string
str2 := string(runes)
fmt.Println(str2) // 输出: 你好

类型转换与算术运算:

在进行算术运算时,操作数必须是相同类型。否则,需要先进行类型转换。

示例:

go 复制代码
package main

import "fmt"

func main() {
    var a int = 10
    var b float64 = 3.14

    // 错误:不能直接相加不同类型
    // c := a + b

    // 正确:先转换类型
    c := float64(a) + b
    fmt.Println(c) // 输出: 13.14
}
相关推荐
掘金码甲哥13 分钟前
当对话模型遇上向量模型,vllm production stack 又该如何应对?
后端
传奇开心果编程36 分钟前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
Bruce_Liuxiaowei40 分钟前
Python 实例赋值遮蔽类属性:一个从不报错的静默陷阱
开发语言·python·语法糖
IT_陈寒1 小时前
Java线程池用错参数,我的服务居然悄悄崩溃了
前端·人工智能·后端
光影少年1 小时前
Express 中间件原理
后端·node.js·express
aramae2 小时前
MySQL内置函数(7)
开发语言·笔记·后端·mysql·其他
徐小夕3 小时前
存量.doc 文档怎么办?JitWord 开源转换库打通旧文档到在线协同全链路
后端·架构·github
ee又momo3 小时前
一次 JWT Token 过期续期的踩坑记录
后端
五彩小白3 小时前
GO语言装饰器语法
golang
二月龙3 小时前
App 瘦身实战:图片、so 库、资源压缩,安装包体积减小 40%
后端