Go语言基础

简介: Go语言基础
Go语言基础

文档: http://doc.golang.ltd/

package main
import "fmt"
func main() {
  fmt.Println("hello,world")
}
变量和常量
变量
var name [类型] = [表达式]
var i,j,k int
m,n := 0,1
常量

常量一般用作全局常量

常量的值在程序编译的时候就确定了,之后不可改变

const LENGTH = 100
const (
  SYS = "Linux"
    TYPE = "PRO"
)

常量生成器iota, iota可以通过枚举创建一系列相关的值,而且不需要明确定义类型

iota每次从0开始取值,逐次+1

const (
  Zero int = iota
    One
    Two
    Three
    Four
)

iota支持在表达式中使用

const(
  p2_0 = 1<<iota    //1
    p2_1              //2
    p2_2              //4
)
指针
  1. 取地址
    &x
  2. 取值
    *p

指针类型的默认初始值为nil

new 函数可以创建一个不需要名称的变量,直接赋值给一个指针

p := new(int) 
*p = 10
包和作用域
  1. 包是数据和函数的集合,go使用包实现程序的模块化
  2. 使用package定义一个包,一般约定使用小写字母对包命名
  3. 一个包意味着一个独立的命名空间
  4. go使用首字母大小写控制可见性,首字母大写在包外可见,首字母小写在包内私有
  5. go中标识符命名为驼峰式
  6. 导入包取别名: import f "fmt"
  7. 一般在package命令之前书写本包的说明
  8. init函数,在包初始化的时候调用,允许初始化的时候自动执行一次
  9. main包中导入了其他包,则会按照导入main包的顺序进行初始化
    每个包先初始化常量,再初始化变量,然后执行init函数,之后开始执行main包下的main函数
  10. 一个包内可以有多个init函数,初始化时按照出现的顺序执行
选择和循环
if
if condition1 {
    
}else if condition2 {
    
}else{
    
}
switch
switch x {
    case xx1:
  case xx2:
    default:
}

每个分支不需要使用break

for

只有for循环

for i:=0;i<100;i++ {
    
}
for{
    
}
arr := []int{1,2,3,4}
for i,v := range arr{
    
}
垃圾回收

go的垃圾回收自动实现 --> 释放不会再使用的程序所占用的空间

著名的垃圾回收机制:引用计数, 分代收集,标记-清除

Go的垃圾回收机制:三色标记算法

基本数据类型

整型,浮点型,复数,布尔类型

bool
byte   --> uint8
rune
int ,uint
int8, uint8
int16
uint16
int32,uint32
int64,uint64
float32
float64
complex64
complex128
uintptr

rune是int32的别名,遍历字符串中每个字符,可以使用这个类型

内置的real() 和 imag() 用于获取复数的实部和虚部

运算符

优先级:从上到下递减

* / % << >> &  &^(与非, AND NOT)
+ - | ^  
==  != < <= > >=
&&
||
  • %仅用于整型间的运算
  • / 存在整除现象
  • 如果算术运算的结果过大,就会出现溢出的现象,无论有无符号,超出高位的bit位部分将被丢弃
    如果原始的数值是有符号类型,数值的正负号可能会发生变化
  • 两个相同类型的值可以用== 或者 != 比较
  • x << n 和 x>> n, n必须为无符号数
数组

数组是具有一定长度且元素数据类型相同的序列

数组的长度是固定的

在go中,数组是值类型,并不是引用类型

定义数组

var a [3]int 
var b [3]int = [3]int{1,2,3}
c := [...]int{1,2,3}
d := [...]int{4,4:1,1:2}

go语言数组长度是数组的一部分

go数组是传递值的,使用数组作为一个函数的参数时,应该使用指针方式,不然会完全复制

字符串

字符串是特殊的数组,字符串是只读的。

字符串的长度和具体元素值都是不可变的 --> 固定长度且元素不可变的字节数组

注意点:字符串s1=s2赋值时,本质不会进行赋值,仅会传递字符串的地址和字节长度,因为字符串不可变 --> 没必要再复制一份

Go源码要求为UTF-8编码,所以一般将字符串按照UTF-8的码点来理解

字符串本质上是一个字节序列,for range不支持非UTF-8编码的遍历

len() 返回的是字符串字节数而非字符个数

对字符串的操作,Go提供几个基础包:

  • strings: 搜索,比较,切分,字符串连接
  • bytes: 底层字节操作, 可以使用[]byte() 转换类型
  • strconv: 字符串与其他类型的转换
  • unicode: 对字符串中的单个字符做判断, IsLetter, IsDigit, IsUpper等

字符串可以强制转换为[]byte 和 []rune类型处理

slice切片

slice是一个拥有相同类型元素的可变长序列,且slice的定义与数组的定义非常像,就是没有长度的数组。

slice的长度不可以超过slice的容量

s := []int{1,2,3,4,5}
ss := make([]int,10)
// 释放
ss = nil

slice传递的是地址,不会复制值

append

通过apped可以在原来的切片上插入元素,可以在开头,结尾,指定位置插入元素或者slice

var a = []int{1,2,3}
a = append(a,33)
a = append(a,[]int{222,333}...)  // ...代表可变参数
// 可以使用append进行删除
a = append(a[:0],a[:3]...) // 只保留前三个元素
copy

复制

a1 := []int{1,1,1,1,1}
b1 := []int{-1,-1,-1}
copy(a1,b1) // 将b1复制到a1

copy的参数必须是slice,不能是数组

map

key-value形式的无序集合

键必须唯一,可以通过键来获取或者更新值

map[k]v

在同一个map, k和v的类型只能是同一种类型

m1 := make(map[string]int)
m2 := map[string]int{
    "k1":11,
    "k2":22,
}
// 删除k1元素
delete(m2,"k1")
  1. 删除一个map中没有的键时,不会报错
  2. map在元素赋值之前必须初始化,要么使用make函数,要么声明时就带着初始值
  3. 未初始化的map时nil值,对未初始化的map执行删除元素,len操作,range操作或者查找元素都不会报错,但是在未初始化之前执行元素赋值就会报错
struct

struct 是值传递

type Person struct{
    // 字段
}

并发编程,channel之间的通信可以使用空结构体作为信号量

  1. struct成员的可见型是通过首字母大小写控制的
  2. 结构体指针必须初始化后才可以使用,仅仅声明结构体指针类型变量,其默认初始值为nil
// 初始化一个struct,返回地址引用
pp := new(Person)  // 使用new
  1. make函数用于slice, map和chan 进行内存分配,返回的是类型本身
  2. new返回初始化的类型对应的指针 --> 结构体初始化中使用较多
struct的组合

使用struct的组合来实现代码复用的效果 --> 类似继承

一个struct可以含有其他struct,达到复用效果

  1. 不可以含自身
  2. struct内的成员可以是执行自己的指针
函数

具名函数和匿名函数

//具名函数
func 函数名(形参列表) 返回值{
}
// 匿名函数
var 变量名 = func(形参列表) 返回值{
}
// 通过变量调用函数   --> 函数指针
闭包

匿名函数可以赋值给一个变量,也可以直接写在一个函数内部

func double() func() int {
    var r int
    return func()int{
        r++
        return r*2
    }
}

类似实现了 类的封装特性

闭包在作用上类似于面向对象编程中类的实例,会把函数和所访问的变量打包到一起,不在关心这个变量原来的作用域

从垃圾回收机制来看,因为闭包函数对外部变量的操作才使其不能被释放回收,从而跨越了作用域的限制

  1. r的定义虽然在匿名函数的外面,但是匿名函数在编译时,把这个变量包装进自己的函数内,从而跨越了作用域的限制,可以让r一直存在,这个匿名函数就是闭包函数
  2. 闭包会将自己用到的变量都保存在内存中,导致变量无法被及时回收,并且可能通过闭包修改父函数使用的变量值,所以在使用时要注意性能和安全性
多返回值及变长参数
// 变长参数
func sum(a int,others...int) int{
    for _,v := range others{
        a + = v
    }
    return a
}
sum(1,2,3,4)
argus := [] int {2,3,4}
sum(1,argus...)
  1. 调用sum的两种方式:
  • 传入所有参数
  • 传入一个切片,注意传递参数时要带…
  1. 可变参数接收时,是一个切片
  2. go中函数的参数只能进行值传递,切片的长度和容量是通过值传递到函数内的,如果在函数内部修改了长度或者容量,函数外的切片是接收不到的,所以需要再返回一个切片。
    基于这个原因,append函数才会每次都返回切片
defer关键字

用于释放资源,会在函数返回之前调用,即使函数崩溃也会在结束前调用。

一个函数内可以有多个defer,在调用的时候按照栈的方式进行。

f,err := os.Open(fileName)
if err != nil {
    panic(err)
}
defer f.Close()
方法

Go没有继承,但是有方法,方法是Go语言面向对象的主要特征。

Go的方法不再属于一个类,而是关联到类型的

type Rectangle struct{
    w,h float64
}
func (r Rectangle) area() float64{
    return r.w * r.h
}

Go语言没有方法重载

要求自定义类型和对应的方法在同一个包中

如果自定义类型本身已经是指针类型,例如: type p*int, 则不允许为该类型定义方法

接口

通过interface关键字定义接口,凡是满足定义的都被认定是该接口的实现。

接口定义了需要被实现的一组函数方法的抽象集合,如果要实现某个接口必须实现该接口的所有方法

type ShapeDesc interface {
    Area() float64
    Perimeter() float64
}

接口断言: 向下转型

Go语言的类型断言可以用x.(T) 表达,x是一个接口类型的具体值表达式,T是一个类型(断言类型)

接口类型的值包括动态类型和动态值,在程序执行时通过动态类型和动态值去调用具体的方法。

注意事项:

  1. 接口中只能声明方法,不可以有具体实现
  2. 接口中不可以声明变量,仅允许声明方法
  3. 实现一个接口,就必须实现接口内声明的所有方法
  4. 接口也可以嵌套组合
空接口

interface{}

可以使用interface{}定义接收任何类型

反射

reflect 是Go提供的动态获取对象类型及结构信息的方式

越是需要编写尽可能通用的代码时,越是需要使用反射

反射可以帮助处理未知类型,灵活

反射中有两个核心类型: reflect.Value 和 reflect.Type, 前者用于存储任意值,后者用于存储任意类型

反射的缺点:

  1. 反射的实现比较复杂,所以反射执行得比较慢,会影响程序得整体性能
  2. 反射得错误在编译时无法发现,到运行时才报错,而且都是panic类型,容易导致程序崩溃
相关文章
|
17天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
27 7
|
17天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
17天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
92 71
|
16天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
100 67
|
19天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
89 62
|
21天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
17天前
|
存储 Go
go语言中映射
go语言中映射
32 11
|
19天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
29 12
|
18天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
26 9
|
22天前
|
安全 Serverless Go
Go语言中的并发编程:深入理解与实践####
本文旨在为读者提供一个关于Go语言并发编程的全面指南。我们将从并发的基本概念讲起,逐步深入到Go语言特有的goroutine和channel机制,探讨它们如何简化多线程编程的复杂性。通过实例演示和代码分析,本文将揭示Go语言在处理并发任务时的优势,以及如何在实际项目中高效利用这些特性来提升性能和响应速度。无论你是Go语言的初学者还是有一定经验的开发者,本文都将为你提供有价值的见解和实用的技巧。 ####