当前位置: 首页 > article >正文

Go语言的使用

✨ Go的基本语法

1. 基本数据类型

在 Go 语言中,不同数据类型占用的内存大小是固定的

数据类型占用内存大小描述
bool1字节布尔值,truefalse
int81字节8位有符号整数,范围 -128127
uint81字节8位无符号整数,范围 0255
int162字节16位有符号整数,范围 -3276832767
uint162字节16位无符号整数,范围 065535
int324字节32位有符号整数,范围 -21474836482147483647
uint324字节32位无符号整数,范围 04294967295
int648字节64位有符号整数,范围 -92233720368547758089223372036854775807
uint648字节64位无符号整数,范围 018446744073709551615
int平台相关通常为 int32int64
uint平台相关通常为 uint32uint64
uintptr平台相关通常为 uint32uint64,用于存储指针值
float324字节32位浮点数
float648字节64位浮点数
complex648字节两个 float32 组成的复数
complex12816字节两个 float64 组成的复数
byte1字节uint8 的别名
rune4字节int32 的别名,用于表示 Unicode 码点

复合数据类型

数据类型占用内存大小描述
string变长字符串,存储实际字符的字节数加上一些额外的元数据(如长度)
[]T变长切片,包含指向底层数组的指针、长度和容量
[n]T固定数组,大小为 n * sizeof(T)
map[K]V变长映射,包含哈希表的元数据和实际存储的数据
struct固定结构体,大小为各字段大小之和,可能包含填充字节以对齐
chan T变长通道,包含通道的元数据和缓冲区(如果有)
interface{}变长接口,包含类型信息和值指针
*T平台相关指针,通常为 4 字节或 8 字节
package main

import "fmt"

func main() {
    var i int = 42
    var f float64 = float64(i)  // 类型转换
    var u uint = uint(f)

    fmt.Printf("i: %d, f: %f, u: %d\n", i, f, u)
}

fmt 包格式化选项

fmt 包的格式化选项整理成表格形式,以便更清晰地查看和理解。以下是一个详细的表格:

格式化符描述示例输入示例输出
%d十进制整数123123
%x十六进制整数1237b
%o八进制整数123173
%b二进制整数1231111011
%c对应整数的 Unicode 字符123{
%f浮点数,小数点后默认6位123.456123.456000
%e科学记数法,小数点前一位,小数点后默认6位123.4561.234560e+02
%E科学记数法,小数点前一位,小数点后默认6位,使用大写E123.4561.234560E+02
%g根据数值大小自动选择 %e%f,去掉尾部的零123.456123.456
%s字符串"hello"hello
%q带引号的字符串,适合打印字符串字面量"hello""hello"
%t布尔值,truefalsetruetrue
%p指针地址&s0xc0000160a0
%v默认格式,适用于任何类型123123
%T类型的名称123int
%%输出百分号本身%%%
%w指定最小宽度,不足时用空格填充%5d 123
%.p指定精度,对于浮点数是小数点后的位数,对于字符串是最大长度%.2f123.46
%-w左对齐%-5d123
package main

import (
    "fmt"
)

func main() {
    // 整数
    fmt.Printf("十进制: %d, 十六进制: %x, 八进制: %o, 二进制: %b, 字符: %c\n", 123, 123, 123, 123, 123)
    // 浮点数
    fmt.Printf("浮点数: %f, 科学记数法: %e, 科学记数法大写E: %E, 自动选择: %g\n", 123.456, 123.456, 123.456, 123.456)
    // 字符串
    fmt.Printf("字符串: %s, 带引号: %q\n", "hello", "hello")
    // 布尔值
    fmt.Printf("布尔值: %t\n", true)
    // 指针
    var s string = "hello"
    fmt.Printf("指针地址: %p\n", &s)
    // 宽度和精度
    fmt.Printf("右对齐: %5d, 左对齐: %-5d, 小数点后两位: %.2f\n", 123, 123, 123.456)
    // 其他选项
    fmt.Printf("默认格式: %v, 类型名称: %T\n", 123, 123)
}

输出结果

十进制: 123, 十六进制: 7b, 八进制: 173, 二进制: 1111011, 字符: {
浮点数: 123.456000, 科学记数法: 1.234560e+02, 科学记数法大写E: 1.234560E+02, 自动选择: 123.456
字符串: hello, 带引号: "hello"
布尔值: true
指针地址: 0xc0000160a0
右对齐:   123, 左对齐: 123  , 小数点后两位: 123.46
默认格式: 123, 类型名称: int

2. 变量和常量

package main

import "fmt"

func main() {
    // 变量声明
    var a int = 10
    var b = 20         // 自动推断类型
    c := 30            // 简短声明(只能在函数内部使用)

    // 常量
    const pi = 3.14

    fmt.Println("a:", a, "b:", b, "c:", c, "pi:", pi)
}
2.1 短声明(short variable declaration)是一种简洁的方式来声明并初始化变量。短声明使用 := 操作符,语法如下:

// variable := value

package main

import "fmt"

func main() {
    // 短声明
    a := 42
    b := "hello"
    c := true

    fmt.Println(a, b, c) // 输出: 42 hello true
}

多变量声明

package main

import "fmt"

func main() {
    x, y := 10, 20
    fmt.Println(x, y) // 输出: 10 20
}

函数返回值

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    // 初始化随机数生成器
    rand.Seed(time.Now().UnixNano())

    // 接收函数返回值
    num := rand.Intn(100)
    fmt.Println(num) // 输出一个 0 到 99 之间的随机数
}
  1. 作用域:短声明只能在函数内部使用,不能在包级别的声明中使用。

  2. 重复声明:在一个作用域内,同一个变量名不能被多次短声明。例如:

    package main
    
    import "fmt"
    
    func main() {
        a := 42
        a := 100 // 编译错误: cannot declare and initialize the same variable twice in the same block
        fmt.Println(a)
    }
    

    但是,如果你已经声明了一个变量,可以在同一个作用域内重新赋值:

    package main
    
    import "fmt"
    
    func main() {
        a := 42
        a = 100 // 合法
        fmt.Println(a) // 输出: 100
    }
    

多变量赋值

package main

import "fmt"

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result) // 输出: Result: 5
    }
}

短声明是 Go 语言中非常实用的特性,可以使代码更加简洁和易读。但在使用时需要注意作用域和重复声明的问题。

2.2 有符号整数的环绕

在编程中,整数环绕(Integer Wraparound)是指当一个整数变量超出其最大或最小值范围时,它的值会自动“环绕”到另一个极端值。这种现象通常发生在有符号整数和无符号整数之间。

有符号整数(如 int8, int16, int32, int64)在超过其最大值时会变为最小值,反之亦然。这是由于它们的内部表示方式(通常是二进制补码)。

示例
package main

import (
	"fmt"
)

func main() {
	var i8 int8 = 127 // int8 的最大值
	fmt.Println("i8 before increment:", i8)
	i8++
	fmt.Println("i8 after increment:", i8) // 输出 -128

	var i8Min int8 = -128 // int8 的最小值
	fmt.Println("i8Min before decrement:", i8Min)
	i8Min--
	fmt.Println("i8Min after decrement:", i8Min) // 输出 127
}
无符号整数的环绕

无符号整数(如 uint8, uint16, uint32, uint64)在超过其最大值时会变为0,反之亦然。这是因为无符号整数没有负数表示,只有正数和0。

package main

import (
	"fmt"
)

func main() {
	var u8 uint8 = 255 // uint8 的最大值
	fmt.Println("u8 before increment:", u8)
	u8++
	fmt.Println("u8 after increment:", u8) // 输出 0

	var u8Zero uint8 = 0 // uint8 的最小值
	fmt.Println("u8Zero before decrement:", u8Zero)
	u8Zero--
	fmt.Println("u8Zero after decrement:", u8Zero) // 输出 255
}
类型最大值最小值环绕示例
int8127-128127 + 1 = -128
-128 - 1 = 127
int1632,767-32,76832,767 + 1 = -32,768
-32,768 - 1 = 32,767
int322,147,483,647-2,147,483,6482,147,483,647 + 1 = -2,147,483,648
-2,147,483,648 - 1 = 2,147,483,647
int649,223,372,036,854,775,807-9,223,372,036,854,775,8089,223,372,036,854,775,807 + 1 = -9,223,372,036,854,775,808
-9,223,372,036,854,775,808 - 1 = 9,223,372,036,854,775,807
uint82550255 + 1 = 0
0 - 1 = 255
uint1665,535065,535 + 1 = 0
0 - 1 = 65,535
uint324,294,967,29504,294,967,295 + 1 = 0
0 - 1 = 4,294,967,295
uint6418,446,744,073,709,551,615018,446,744,073,709,551,615 + 1 = 0
0 - 1 = 18,446,744,073,709,551,615
  1. 溢出检测:在关键应用中,应该注意整数溢出的问题,可以通过检查变量是否在预期范围内来避免潜在的错误。
  2. 编译器优化:某些编译器可能会优化掉显式的溢出检查,因此在编写代码时要特别小心。
  3. 安全编程:使用更大的整数类型(如 int32int64)可以减少溢出的风险,但在某些情况下可能会增加内存使用。
3.2 math/big 包提供了用于高精度计算的整数、有理数和浮点数类型。

这些类型可以处理任意大小的数值,非常适合需要高精度计算的场景。以下是对 math/big 包中主要类型的介绍和使用示例。

  1. big.Int:用于表示任意大小的整数。
  2. big.Rat:用于表示任意精度的有理数(分数)。
  3. big.Float:用于表示任意精度的浮点数。

big.Int 的使用

big.Int 是最常用的类型,用于处理大整数。以下是一些基本操作的示例:

导入包
import "math/big"

big.Int 实例

// 通过 NewInt 创建一个 big.Int 实例
zero := big.NewInt(0)
one := big.NewInt(1)

// 通过 SetInt64 创建一个 big.Int 实例
largeNumber := big.NewInt(0).SetInt64(1234567890123456789)

// 通过 SetString 创建一个 big.Int 实例
veryLargeNumber, ok := new(big.Int).SetString("123456789012345678901234567890", 10)
if !ok {
    panic("invalid number")
}
// 加法
sum := new(big.Int).Add(one, one) // sum = 2
// 减法
difference := new(big.Int).Sub(one, zero) // difference = 1
// 乘法
product := new(big.Int).Mul(one, largeNumber) // product = 1234567890123456789
// 除法
quotient := new(big.Int).Div(veryLargeNumber, largeNumber) // quotient = 100000000000000000000000000
// 模运算
remainder := new(big.Int).Mod(veryLargeNumber, largeNumber) // remainder = 0
// 幂运算
power := new(big.Int).Exp(largeNumber, big.NewInt(2), nil) // power = 1234567890123456789^2
// 比较
cmp := veryLargeNumber.Cmp(largeNumber) // cmp > 0 表示 veryLargeNumber > largeNumber

big.Rat 用于表示任意精度的有理数(分数)。

// 通过 NewRat 创建一个 big.Rat 实例
half := big.NewRat(1, 2)
// 通过 SetFloat64 创建一个 big.Rat 实例
piRat := new(big.Rat).SetFloat64(3.141592653589793)
// 通过 SetString 创建一个 big.Rat 实例
fraction, ok := new(big.Rat).SetString("1/3")
if !ok {
    panic("invalid fraction")
}
// 加法
sumRat := new(big.Rat).Add(half, half) // sumRat = 1
// 减法
differenceRat := new(big.Rat).Sub(half, fraction) // differenceRat = 1/6
// 乘法
productRat := new(big.Rat).Mul(half, piRat) // productRat = 1.5707963267948965
// 除法
quotientRat := new(big.Rat).Quo(piRat, half) // quotientRat = 6.283185307179586
// 比较
cmpRat := piRat.Cmp(fraction) // cmpRat > 0 表示 piRat > fraction

big.Float 用于表示任意精度的浮点数。

// 通过 NewFloat 创建一个 big.Float 实例
pi := big.NewFloat(3.141592653589793)

// 通过 SetPrec 设置精度
pi.SetPrec(100) // 设置精度为 100 位

// 通过 SetString 创建一个 big.Float 实例
largeFloat, _, err := big.ParseFloat("12345678901234567890.12345678901234567890", 10, 0, big.ToNearestEven)
if err != nil {
    panic("invalid float")
}
// 加法
sumFloat := new(big.Float).Add(pi, pi) // sumFloat = 6.283185307179586
// 减法
differenceFloat := new(big.Float).Sub(pi, pi) // differenceFloat = 0
// 乘法
productFloat := new(big.Float).Mul(pi, pi) // productFloat = 9.869604401089358
// 除法
quotientFloat := new(big.Float).Quo(pi, pi) // quotientFloat = 1
// 比较
cmpFloat := pi.Cmp(largeFloat) // cmpFloat < 0 表示 pi < largeFloat

math/big 包提供了强大的工具来处理大整数、有理数和浮点数,适用于需要高精度计算的场景。通过这些示例,您可以更好地理解和使用 math/big 包中的主要类型和方法。

2.4 Unicode 码点(Code Point)

可以使用不同的编码方式来表示。常见的 Unicode 编码方式包括 UTF-8、UTF-16 和 UTF-32。每种编码方式都有其特点和适用场景。以下是这三种编码方式的详细介绍:

UTF-8 是一种可变长度的编码方式,广泛用于互联网和现代操作系统中。它具有以下特点:

  • 兼容 ASCII:对于 ASCII 字符(码点范围 U+0000U+007F),UTF-8 编码与 ASCII 完全相同,使用 1 个字节。

  • 可变长度:对于其他 Unicode 码点,UTF-8 使用 1 到 4 个字节来编码。

  • 自同步:可以从任意位置开始解码,即使中间有错误也不会影响后续的解码。

  • 1 字节0xxxxxxxU+0000U+007F

  • 2 字节110xxxxx 10xxxxxxU+0080U+07FF

  • 3 字节1110xxxx 10xxxxxx 10xxxxxxU+0800U+FFFF

  • 4 字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxxU+10000U+10FFFF

UTF-8 示例
package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    str := "Hello, 世界!"

    for i, c := range str {
        fmt.Printf("Index: %d, Rune: %U, Char: %c, UTF-8: % x\n", i, c, c, []byte(string(c)))
    }
}
//Index: 0, Rune: U+0048, Char: H, UTF-8: 48
//Index: 1, Rune: U+0065, Char: e, UTF-8: 65

UTF-16 示例
package main

import (
    "fmt"
    "encoding/json"
)

func main() {
    str := "Hello, 世界!"

    // 将字符串转换为 UTF-16 编码
    utf16 := json.RawMessage(str).EncodeUTF16()

    for i, c := range utf16 {
        fmt.Printf("Index: %d, UTF-16: %04x\n", i, c)
    }
}
//Index: 0, UTF-16: 0048
//Index: 1, UTF-16: 0065
...
UTF-32 示例
package main

import (
    "fmt"
)

func main() {
    str := "Hello, 世界!"

    // 将字符串转换为 UTF-32 编码
    utf32 := []rune(str)

    for i, c := range utf32 {
        fmt.Printf("Index: %d, UTF-32: %08x\n", i, uint32(c))
    }
}
//Index: 0, UTF-32: 00000048
//Index: 1, UTF-32: 00000065
...
  • UTF-8:可变长度,兼容 ASCII,广泛用于互联网和现代操作系统。
  • UTF-16:变长编码,主要用于 Windows 和 Java,对于 BMP 字符使用 2 个字节,对于辅助平面字符使用 4 个字节。
  • UTF-32:固定长度,每个码点使用 4 个字节,编码和解码简单直接。
2.5 字符串是一种不可变的字节序列。

创建字符串

// 直接赋值
str1 := "Hello, World!"

// 使用反引号创建多行字符串
str2 := `This is a
multi-line
string.`

// 使用 fmt.Sprintf 创建格式化字符串
str3 := fmt.Sprintf("The answer is %d", 42)

字符串拼接

// 使用 + 运算符
str4 := "Hello" + " " + "World"

// 使用 fmt.Sprintf
str5 := fmt.Sprintf("%s %s", "Hello", "World")

// 使用 strings.Join
parts := []string{"Hello", "World"}
str6 := strings.Join(parts, " ")

字符串长度

length := len("Hello, World!") // length = 13

字符串索引

str := "Hello, World!"
firstChar := str[0] // 'H'
lastChar := str[len(str)-1] // '!'

子字符串

str := "Hello, World!"
subStr1 := str[0:5]   // "Hello"
subStr2 := str[7:]    // "World!"
subStr3 := str[:5]    // "Hello"
subStr4 := str[len(str)-6:] // "World!"

字符串比较

str1 := "Hello"
str2 := "Hello"
str3 := "World"

isEqual := str1 == str2 // true
isNotEqual := str1 != str3 // true

字符串查找

str := "Hello, World!"

// 查找子字符串的位置
index := strings.Index(str, "World") // index = 7

// 查找子字符串是否存在
contains := strings.Contains(str, "World") // true

// 查找前缀
hasPrefix := strings.HasPrefix(str, "Hello") // true

// 查找后缀
hasSuffix := strings.HasSuffix(str, "World!") // true

字符串替换

str := "Hello, World!"
newStr := strings.Replace(str, "World", "Go", 1) // "Hello, Go!"

字符串分割

str := "a,b,c,d"
parts := strings.Split(str, ",") // []string{"a", "b", "c", "d"}

字符串修剪

str := "  Hello, World!  "
trimmed := strings.TrimSpace(str) // "Hello, World!"

字符串转换

str := "Hello, World!"

// 转换为小写
lower := strings.ToLower(str) // "hello, world!"

// 转换为大写
upper := strings.ToUpper(str) // "HELLO, WORLD!"

// 转换为驼峰式
camel := strings.Title(str) // "Hello, World!"

字符串格式化

// 使用 fmt.Sprintf 进行格式化
formatted := fmt.Sprintf("The answer is %d", 42) // "The answer is 42"

字符串遍历

str := "Hello, 世界!"

// 遍历每个字节
for i := 0; i < len(str); i++ {
    fmt.Printf("%c ", str[i])
}

// 遍历每个 Unicode 码点
for i, c := range str {
    fmt.Printf("Index: %d, Rune: %c\n", i, c)
}

3. 控制结构

条件语句
package main

import "fmt"

func main() {
    age := 18

    if age >= 18 {
        fmt.Println("You are an adult.")
    } else {
        fmt.Println("You are a minor.")
    }

    // switch语句
    day := 2
    switch day {
    case 1:
        fmt.Println("Monday")
    case 2:
        fmt.Println("Tuesday")
    default:
        fmt.Println("Other day")
    }
}
循环语句

Go语言中只有一种循环结构:for

package main

import "fmt"

func main() {
    // 基本的for循环
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }

    // 类似while循环
    count := 0
    for count < 3 {
        fmt.Println(count)
        count++
    }

    // 遍历数组
    arr := []string{"apple", "banana", "cherry"}
    for index, value := range arr {
        fmt.Printf("index: %d, value: %s\n", index, value)
    }
}

4. 函数和多返回值

package main

import "fmt"

// 定义一个有返回值的函数
func add(x int, y int) int {
    return x + y
}

// 多返回值函数
func divide(dividend, divisor int) (int, int) {
    quotient := dividend / divisor
    remainder := dividend % divisor
    return quotient, remainder
}

func main() {
    sum := add(10, 5)
    fmt.Println("Sum:", sum)

    quotient, remainder := divide(10, 3)
    fmt.Printf("Quotient: %d, Remainder: %d\n", quotient, remainder)
}

5. 指针

package main

import "fmt"

func main() {
    x := 10
    ptr := &x            // 获取变量的地址
    fmt.Println("Address of x:", ptr)
    fmt.Println("Value of x:", *ptr)  // 通过指针访问变量值
}

6. 结构体与方法

package main

import "fmt"

// 定义一个结构体
type Person struct {
    Name string
    Age  int
}

// 结构体方法
func (p Person) Greet() {
    fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.Name, p.Age)
}

func main() {
    person := Person{Name: "Alice", Age: 25}
    person.Greet()
}

7. 接口和多态

package main

import "fmt"

// 定义一个接口
type Animal interface {
    Speak() string
}

// Dog类型实现了Animal接口
type Dog struct{}
func (d Dog) Speak() string {
    return "Woof!"
}

// Cat类型实现了Animal接口
type Cat struct{}
func (c Cat) Speak() string {
    return "Meow!"
}

func main() {
    animals := []Animal{Dog{}, Cat{}}
    for _, animal := range animals {
        fmt.Println(animal.Speak())
    }
}

8. 并发编程:goroutines 和 channels

package main

import (
    "fmt"
    "time"
)

// 函数,用于展示goroutine
func printMessage(message string) {
    for i := 0; i < 3; i++ {
        fmt.Println(message)
        time.Sleep(500 * time.Millisecond)
    }
}

func main() {
    go printMessage("Hello from goroutine")  // 启动goroutine
    printMessage("Hello from main")

    // 使用通道
    ch := make(chan string)
    go func() {
        ch <- "Data sent to channel"
    }()

    msg := <-ch  // 从通道接收数据
    fmt.Println("Received:", msg)
}

9. 错误处理

package main

import (
    "errors"
    "fmt"
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}

这些示例展示了Go语言的一些基本语法和特色特性。在实际开发中,还可以结合Go的标准库及第三方库来实现更多功能。


http://www.kler.cn/a/376283.html

相关文章:

  • 1分钟解决Excel打开CSV文件出现乱码问题
  • 从线性代数到unity mvp矩阵
  • 电脑软件:推荐一款免费且实用的电脑开关机小工具
  • 11月01日,每日信息差
  • Java Executor ScheduledExecutorService 源码
  • AutoGLM:智谱AI的创新,让手机成为你的生活全能助手
  • 高级SQL技巧详解与实例
  • 华为机试HJ17 坐标移动
  • 《手写Spring渐进式源码实践》实践笔记(第十四章 通过注解自动注入属性信息)
  • JDK动态代理为什么只能代理有接口的类?
  • 【原创分享】生产环境JAVA中间件性能优化调优要点和案例分析
  • 面向过程与面向对象
  • nginx-proxy-manager实现反向代理+自动化证书(实战)
  • 前端项目【本科期间】
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-27
  • uniapp 小程序 H5 app 价格计算 避免精度丢失
  • 深入探讨 Tantivy 及其在 Milvus 中的应用:倒排索引库对比与选择
  • Android Studio开发学习(五)———LinearLayout(线性布局)
  • 微信小程序 uniapp 腾讯地图的调用
  • 设计模式之责任链的通用实践思考
  • C语言静态库
  • 数据结构之链式结构二叉树的实现(初级版)
  • FRIDA-JSAPI:Process使用
  • HTTP 405 Method Not Allowed:解析与解决
  • 【spark】——spark面试题(1)
  • 基于YOLO11/v10/v8/v5深度学习的农作物类别检测与识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】