当前位置: 首页 > 工具软件 > Ciao-Go > 使用案例 >

Golang基础

杨君之
2023-12-01

引言:快速有效的学习需要做一个总结,今天,在学习完了所有的Go语言基础之后进行一个总结型复习,然后进行下一个阶段的学习

常量

常量使用关键字 const定义,用于存储不会改变的数据

const identifier [type] = value
const Pi = 3.1415

const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6

常量可以用作枚举

const (
	Unknown = 0
	Female = 1
	Male = 2
)

iota:第一个iota等于0,在新一行被使用时,它的值就自动加1
赋值一个常量时,之后没赋值的常量都会使用上一行的赋值表达式
赋值两个常量,iota只会增加一次,而不会因为使用了两次就增长两次
可以与位运算结合,表示资源的使用案例

const (
	Open = 1 << iota  // 0001
	Close             // 0010
	Pending           // 0100
)

变量

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

var identifier type

当一个变量被声明之后,系统会赋予它该类型的零值
inte为0,float为0.0,bool为false,string为空字符串
可以进行声明阶段的赋值,
尽管Go编译器可以根据变量的值来自动推断类型,但是在特别需要的时候仍要自己来声明变量类型

var n int64 = 2

runtime包中的函数os.Geten可以换取环境变量中的值
go env
值类型:int, bool, float, string,数组,结构
可以比较大小
引用类型:指针。slices,maps,channel
被引用的变量存储到堆中,便于进行垃圾回收
引用类型的变量存贮的是内存地址
fmt,Sprintf与Printf,前者将格式化后的字符串以返回值的形式返回给调用者
变量除了可以在全局变量中初始化,也可以在init变量中初始化,iinit是一个特殊的函数,每个包完成初始化之后自动执行,优先级比main函数高

基本类型和运算符

uint8/int8 2^8 256 int8 = byte
uint16/int16 z^16 65535
uint32/int 32 2^32 4294967295 int32 = rune
uint64/int64 2^64 18446744073709551615

  • 一元运算符
    按位与& 按位或| 按位异或^
    算数运算符
    运算符与优先级
    类型别名
    字符类型

字符串

\n, \r \t \u \
字符串包含关系
strings.Contains(s, substr string ) bool
返回字符串str在字符串s中最后出现位置的索引
strings.LastIndex( s, str string) int
需要查询非ASCLL编码的字符在夫字符串的位置
strings.IndexRune(s string, r rune) int
Count用于计算字符串str在字符串s中出现的非重叠次数
strings.Count(s, str string) int
Repeat用于重复count次字符串s并返回一个新的字符串
strings,Reapeat(a, count int) string

  • 修剪字符串
    strings.TrimSpace(s)剔除字符串开头和结尾的空白符号,想要剔除指定字符,则可以使用strings.Trim(s, “cut”)
    strings.Split(s, sp) 用于自定义符号来对指定字符串进行分割,同样返回slice
  • 拼接slice到字符串
    strings.Join(s1 [ ]strings, sep string ) string
  • 从字符串中读取内容
    Read()从[ ]byte中读取内容
    ReadByte()和ReadRune( )从字符串种内读取下一个byte或者rune

时间和日期

  • time.Day() time.Time() time.Minyte() time.Now()

指针

一个指针变量可以指向任何一个值的内存地址
可以声明指针指向的任何类型的值来表明它的原始性或结构性,在指针类型前面加上*号,可以获取指针指向的内容,*号是一个类型更改器。使用一个指针引用一个值称为间接引用

var p *string = &s
*p = "ciao"

被指向的变量也保存到内存中,直到没有任何指针指向它们,所以从它们被创建就开始由相互独立的生命周期

指针传递 只占用4个到8个字节

控制结构

if-else
switch
select
for pos, char := range str2
for rang
os.Exit(1)
此处的退出代码可以使用外部脚本获取到

函数

函数也可以以申明的方式被使用,作为一个函数类型
type binOp func(int, int)int

func min(s ...int) int {
	if len(s)==0 {
		return 0
	}
	min := s[0]
	for _, v := range s {
		if v < min {
			min = v
		}
	}
	return min
}

defer的使用
defer.Unlock
defer printFooter()
defer disconnectFromDB()
一些内置函数
close len cap new make
copy append panic recover print println complex real imag

递归函数

package main

import "fmt"

func main() {
    result := 0
    for i := 0; i <= 10; i++ {
        result = fibonacci(i)
        fmt.Printf("fibonacci(%d) is: %d\n", i, result)
    }
}

func fibonacci(n int) (res int) {
    if n <= 1 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}

闭包 就是把返回的函数存到变量中

func Adder(a int) func(b int) int {
    return func(b int) int {
        return a + b
    }

在闭包中使用到的变量也可以在闭包函数中声明 可以在外部声明

var g int
go func(i int) {
    s := 0
    for j := 0; j < i; j++ { s += j }
    g = s
}(1000) 

一个返回值是另一个函数的函数被成为工厂函数

func MakeAddSuffix(suffix string) func(string) string {
    return func(name string) string {
        if !strings.HasSuffix(name, suffix) {
            return name + suffix
        }
        return name
    }
}

记录函数执行的时间
end.Sub(start)

start := time.Now()
longCalculation()
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)

容器

数组 var identifier [len]type
切片 var slice1 []type = arr1[start:end] 长度可变的数组
map var map1 map[string]int
使用new()分配一个引用对象,会获得一个空指针,相当于声明了一个未初始化的变量并取了它的地址
map类型的切片 items := make([ ]map[int]int, 5)

new (T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 * T 的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。指针 指针 指针
make(T) 返回一个类型为 T 的初始值,它只适用于 3 种内建的引用类型:切片、map 和 channel

for ix, value := range slice1 {
    ...
}

第一个返回值 ix 是数组或者切片的索引,第二个是在该索引位置的值;他们都是仅在 for 循环内部可见的局部变量。value 只是 slice1 某个索引位置的值的一个拷贝,不能用来修改 slice1 该索引位置的值。

将在字符串中对正则表达式进行匹配。

如果是简单模式,使用 Match 方法便可:
ok, _ := regexp.Match(pat, []byte(searchIn))
变量 ok 将返回 true 或者 false, 我们也可以使用 MatchString:
ok, _ := regexp.MatchString(pat, searchIn)

结构定义

type identifier struct {
    field1 type1
    field2 type2
    ...
}

per2 := new(Person)
new会指向这个对象,即指针

垃圾收集器(GC),

会处理这些事情,它搜索不再使用的变量然后释放它们的内存。可以通过 runtime 包访问 GC 进程
runtime.GC() 函数可以显式的触发 GC,但这只在某些罕见的场景下才有用,比如当内存资源不足时调用 runtime.GC(),它会在此函数执行的点上立即释放一大片内存,此时程序可能会有短时的性能下降(因为 GC 进程在执行)。

接口

  • 通过它可以实现很多面向对象的特性。接口提供了一种方式来 说明 对象的行为
  • 接口里也不能包含变量。
    即 接口是对面向对象的一种实现
  • 指向接口值的指针是非法的,它们不仅一点用也没有,还会导致代码错误。
  • 接收一个(或多个)接口类型作为参数的函数,其实参可以是任何实现了该接口的类型。 实现了某个接口的类型可以被传给任何以此接口为参数的函数 。
  • Sorts接口排序
    data.Less data.Swap

封装 继承 多态

  • 封装(数据隐藏):和别的 OO 语言有 4 个或更多的访问层次相比,Go 把它简化为了 2 层(参见 4.2 节的可见性规则):
    1)包范围内的:通过标识符首字母小写,对象 只在它所在的包内可见
    2)可导出的:通过标识符首字母大写,对象 对所在包以外也可见
  • 继承:用组合实现:内嵌一个(或多个)包含想要的行为(字段和方法)的类型;多重继承可以通过内嵌多个类型实现
  • 多态:用接口实现:某个类型的实例可以赋给它所实现的任意接口类型的变量。类型和接口是松耦合的,并且多重继承可以通过实现多个接口实现。Go 接口不是 Java 和 C# 接口的变体,而且:接口间是不相关的,并且是大规模编程和可适应的演进型设计的关键。
  • 一个对象只要实现了接口中的所有方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表,就是一个对象
type People interface {
	Speak()
}

type student struct {
}

func (stu student) Speak() {
    fmt.Println("hello")
}

读写数据

Scanf
Scanln
都是对标准输入的读取
inputReader := bufio.NewReader(os.Stdin)
带缓冲的读取数据

buf := make([]byte, 1024)
...
n, err := inputReader.Read(buf)
if (n == 0) { break}


   outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
    if outputError != nil {
        fmt.Printf("An error occurred with file opening or creation\n")
        return  
    }
    defer outputFile.Close()

os.O_RDONLY:只读
os.O_WRONLY:只写
os.O_CREATE:创建:如果指定文件不存在,就创建该文件。
os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为 0。
* 文件拷贝

```go

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()

#flag.Parse() 扫描参数列表(或者常量列表)并设置 flag
(recover)内建函数被用于从 panic 或 错误场景中恢复:让程序可以从 panicking 重新获得控制权,停止终止过程进而恢复正常执行。

func protect(g func()) {
    defer func() {
        log.Println("done")
        // Println executes normally even if there is a panic
        if err := recover(); err != nil {
        log.Printf("run time panic: %v", err)
        }
    }()
    log.Println("start")
    g() //   possible runtime-error
}
 类似资料: