go 详解

本文介绍了Go语言的主要特点,包括自动垃圾回收、丰富的内置类型、并发编程等,并提供了环境安装指南,展示了基本语法如包声明、函数定义及数据类型,适合初学者快速上手。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要特点

  • 自动垃圾回收
  • 丰富的内置类型
  • 函数多返回值
  • 错误处理
  • 匿名函数和闭包
  • 类型和接口
  • 并发编程
  • 发射
  • 语言交互性

环境安装

windows

安装包地址:https://golang.org/dl/。或https://golang.google.cn/dl/。

windows上安装完后可以直接在cmd中运行go

Linux
sudo apt install golang-go

语言结构

  • 包声明

  • 引入包

  • 函数

  • 变量

  • 语句&表达式

  • 注释

    package main

    import "fmt"
    
    func main() {
       /* 这是我的第一个简单的程序 */
       fmt.Println("Hello, World!")
    }
    

注:

  • 需要注意的是 { 不能单独放在一行
  • 在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

数据类型

布尔型

布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。

数字类型

uint8 uint16 uint32 uint64 int8 int16 int32 int64 float32 float32 complex64(32 位实数和虚数) complex128(64 位实数和虚数)

byte 类似 uint8

rune 类似 int32
uint 32 或 64 位
int 与 uint 一样大小
uintptr 无符号整型,用于存放一个指针

派生类型

​ (a) 指针类型(Pointer)
​ (b) 数组类型
​ © 结构化类型(struct)
​ (d) Channel 类型
​ (e) 函数类型
​ (f) 切片类型
​ (g) 接口类型(interface)
​ (h) Map 类型

变量

声明变量的一般形式是使用 var 关键字: var identifier type

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数
第一种,指定变量类型

​ var a *int
​ var a []int
​ var a map[string] int
​ var a chan int
​ var a func(string) int
​ var a error // error 是接口

第二种,根据值自行判定变量类型。

​ var v_name = value

省略 var, 注意 := 左侧如果没有声明新的变量,就产生编译错误

格式: v_name := value

var intVal int 
intVal :=1 // 这时候会产生编译错误
intVal,intVal1 := 1,2 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句
多变量声明

​ //类型相同多个变量, 非全局变量
​ var vname1, vname2, vname3 type
​ vname1, vname2, vname3 = v1, v2, v3

var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断

vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
实例
// 第一种写法
var num1 int = 1
var num2 int = 2
var num3 int = 3
或者
var num1 = 1
var num2 = 2
var num3 = 3

// 第二种写法
var num1,num2,num3 int = 1,2,3
或者
var num1, num2, num3 = 1,2,3

// 第三种写法
var (
    num1 int = 1
    num2 int = 2
    num3 int = 3
)或
var (
    num1 = 1
    num2 = 2
    num3 = 3  
)

常量

格式:const identifier [type] = value

显式类型定义: const b string = "abc"
隐式类型定义: const b = "abc"

运算符

      • / % ++ – == != < > >= <=

&& || ! & | ^ << >> = += -= *= /= %= <<= >>= &= ^= |=

条件语句

if

​ if 布尔表达式 {
​ /* 在布尔表达式为 true 时执行 /
​ } else {
​ /
在布尔表达式为 false 时执行 */
​ }

switch

​ switch var1 {
​ case val1:
​ …
​ case val2:
​ …
​ default:
​ …
​ }

select

​ select {
​ case communication clause :
​ statement(s);
​ case communication clause :
​ statement(s);
​ /* 你可以定义任意数量的 case /
​ default : /
可选 */
​ statement(s);
​ }

  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。 否则:如果有 default 子句,则执行该语句。如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值

循环语句

for

​ for init; condition; post { }
​ for condition { }
​ for { } //死循环

  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。
	func main() {
	   var b int = 15
	   var a int
	   numbers := [6]int{1, 2, 3, 5}
	
	   /* for 循环 */
	   for a := 0; a < 10; a++ {
	      fmt.Printf("a 的值为: %d\n", a)
	   }
	
	   for a < b {
	      a++
	      fmt.Printf("a 的值为: %d\n", a)
	   }
	
	   for i,x:= range numbers {
	      fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
	   }  
	}

方法

func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {      函数体  } 
  • 指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的
  • 非指针接收器时,Go 语言会在代码运行时将接收器的值复制一份。在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。

函数

格式:

func function_name( [parameter list] ) [return_types] {
   函数体
}
  • func:函数由 func 开始声明

  • function_name:函数名称,函数名和参数列表一起构成了函数签名

  • 参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。

  • return_types:返回类型,有些功能不需要返回值,这种情况下 return_types 不是必须的。

    func swap(x, y string) (string, string) {
    return y, x
    }

    func main() {
       a, b := swap("Mahesh", "Kumar")
       fmt.Println(a, b)
    }
    
    /* 函数返回两个数的最大值 */
    func max(num1, num2 int) int {
       /* 定义局部变量 */
       var result int
    
       if (num1 > num2) {
          result = num1
       } else {
          result = num2
       }
       return result
    }
    

数组

格式:var variable_name [SIZE] variable_type

var balance [10]float32

初始化:

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:
var balance = […]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

balance[4] = 50.0

指针

格式:var var_name *var-type

var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

结构体

格式:

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}
type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
    // 创建一个新的结构体
    fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
    // 忽略的字段为 0 或 空
   fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}

枚举

在golang中并没有枚举类型,但可根据iota特性进行枚举类型的定义

详见iota使用

切片(Slice)

可以声明一个未指定大小的数组来定义切片:

var identifier []type

或使用make()函数来创建切片:

var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)

空(nil)切片:一个切片在未初始化之前默认为 nil,长度为 0

可变参数

声明可变参数函数时,需要在参数列表的最后一个参数类型之前加上省略符号“…”,这表示该函数会接收任意数量的该类型参数。

func sum(vals ...int) int {
    total := 0
    for _, val := range vals {
        total += val
    }
    return total
}

sum函数返回任意个int型参数的和。在函数体中,vals被看作是类型为[] int的切片。sum可以接收任意数量的int型参数:

fmt.Println(sum())           // "0"
fmt.Println(sum(3))          // "3"
fmt.Println(sum(1, 2, 3, 4)) // "10"

标准库

https://studygolang.com/pkgdoc

包引用

同一个包里面,不同文件之间,不需要 import,直接用就好。不同包的话,需要引用包,只能使用大写字母开头的方法 ,变量 等等,小写子母开头的只能包内使用。大写字母开头的变量,方法暴露给其他包用的,包内的话可以随便引用。

直接引用

import “fmt”

import “os”

将包一块引入
 import (
      "fmt"
      "os"
    )
相对路径
import   "./model"  // 当前文件同一目录的 model 目录
绝对路径
import   "shorturl/model"  // 加载 GOPATH/src/shorturl/model 模块
点操作
import( 
    . "fmt" 
) 

这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名 fmt.Println( “我爱北京天安门” )可以省略的写成 Println( “我爱北京天安门” )。

别名操作
import( 
    f "fmt" 
) 
f.Println( "我爱北京天安门" )
下划线操作
import ( 
    “database/sql” 
    _ “github.com/ziutek/mymysql/godrv” 
) 

下滑线 操作其实只是引入该包。当导入一个包时,它所有的 init() 函数就会被执行,但有些时候并非真的需要使用这些包,仅仅是希望它的 init() 函数被执行而已。这个时候就可以使用下滑线操作引用该包了。即使用下滑线操作引用包是无法通过包名来调用包中的导出函数,而是只是为了简单的调用其 init() 函数。

new()和make()区别

  • new 的作用是初始化一个指向类型的指针(*T),make 的作用是为 slice,map 或 chan 初始化并返回引用(T)。
  • func new(Type) *Type
  • func make(Type, size IntegerType) Type

下划线

忽略返回值
v1, v2, _ := function(...)
某个函数返回三个参数,但是我们只需要其中的两个,另外一个参数可以忽略
下划线在import中

让导入的包做初始化,而不使用包中其他功能

range

返回的第一个索引是连续的,可以看到第二个值都是整型数字

func rangeString() {
    datas := "aAbB"

    for k, d := range datas {
        fmt.Printf("k_addr:%p, k_value:%v\nd_addr:%p, d_value:%v\n----\n", &k, k, &d, d)
    }
}

k_addr:0xc420014148, k_value:0
d_addr:0xc420014150, d_value:97
k_addr:0xc420014148, k_value:1
d_addr:0xc420014150, d_value:65
k_addr:0xc420014148, k_value:2
d_addr:0xc420014150, d_value:98
k_addr:0xc420014148, k_value:3
d_addr:0xc420014150, d_value:66

type

定义别名

例如:type name string // name类型与string等价,就是将一个string类型起一个别名叫做name

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值