0
点赞
收藏
分享

微信扫一扫

GO学习笔记


GO学习笔记

  • ​​GO​​
  • ​​变量​​
  • ​​常量​​
  • ​​基本数据类型​​
  • ​​整形​​
  • ​​浮点数​​
  • ​​复数​​
  • ​​布尔型​​
  • ​​字符串​​
  • ​​流程控制​​
  • ​​条件判断​​
  • ​​循环语句​​
  • ​​运算符​​
  • ​​复杂数据类型​​
  • ​​数组​​
  • ​​切片​​
  • ​​指针​​
  • ​​map​​
  • ​​函数​​
  • ​​defer​​
  • ​​函数类型和变量​​
  • ​​匿名函数​​
  • ​​闭包​​
  • ​​结构体​​
  • ​​自定义类型和类型别名​​
  • ​​结构体​​
  • ​​结构体指针和结构体初始化​​
  • ​​方法和接受者​​
  • ​​接口​​
  • ​​值接收者和指针接收者​​
  • ​​接口和类型关系​​
  • ​​空接口​​
  • ​​包​​
  • ​​文件操作​​
  • ​​打开和关闭文件​​
  • ​​读文件​​
  • ​​文件写入​​
  • ​​标准输入和输出​​
  • ​​内置包​​
  • ​​time​​
  • ​​时间戳​​

GO

基本程序框架

package main  // 表明这是一个可执行文件

import "fmt" // 引入的库

func main() { // 主函数入口
fmt.Print("Hello World")
}

变量

函数外只能放置变量的声明,不可放定义

// fm.Println("Hello World")非法
func main() {
// do something
}

函数外声明变量,函数内定义变量(非全局变量声明了必须使用

var s1 string
// 批量声明
var {
s1 string
s2 int
s3 bool
}
func main() {
s1 = "lh"
s2 = 2
s3 = true
}

变量赋值(声明变量同时进行赋值)

// 1)
var s1 string = "lh"
// 2) 类型推导
var s2 = "lh"
// 3) 简短变量声明,只能在函数中使用
var s3 := "lh"

匿名变量:在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量

func foo() {
return 10, "hl"
}
func main() {
_, b := foo()
}

常量

常量在定义的时候必须赋值

const s1 = "lh"
// 批量赋值
const {
s1 = "s2"
s2 = "s1"
}
// 如果批量赋值没有赋值,则按照第一个进行自动赋值
const {
s1 = "s2"
s2
s3
}

如果不是指定确定的值,可以使用iota代替,const中每新增一行常量声明将iota计数一次(有时也可用自定义值代替),可以理解为const的行索引

const {
a1 = iota // 默认为0
a2 // 默认为1
a3 // 默认为2
a4 // 默认为3
}

const {
a1 = iota + 1, a2 = iota + 2 // a1 = 0 + 1,a2 = 0 + 2
a3 = iota + 1, a4 = iota + 2 // a3 = 1 + 1,a4 = 1 + 2
}

基本数据类型

整形

int8  // 对应无符号uint8
int16 // 对应无符号uint16
int32 // 对应无符号uint32
int64 // 对应无符号uint64
uintptr // 无符号整形,用于存放一个指针

fmt.Printf("%d")  // 十进制
fmt.Printf("%b") // 二进制
fmt.Printf("%o") // 八进制
fmt.Printf("%x") // 十六进制

浮点数

float32
float64

复数

complex64
complex128

布尔型

true
false

字符串

方法

介绍

len(str)

求长度

+或fmt.Sprintf

拼接字符串

strings.Split

分割

strings.contains

判断是否包含

strings.HasPrefix,strings.HasSuffxc

前缀/后缀判断

strings.IndexO),strings.LastIndex0

子串出现的位置

流程控制

条件判断

单分支

package main

import "fmt"

func main() {
var s1 = 2
if s1 > 1 {
fmt.Print("Hello World!")
}
}

双分支

func main() {
var s1 = 2
if s1 > 1 {
fmt.Print("Hello World!")
}
else {
fmt.Print("Hello Linux!")
}
}

多分支

func main() {
var s1 = 2
if s1 > 1 {
fmt.Print("Hello World!")
}
else if s1 > 2 {
fmt.Print("Hello Linux!")
}
else {
fmt.Print("Hello Windows!")
}
}

循环语句

条件循环

for i := 0; i < 10; i++ {
fmt.Print("Hello World")
}

var i := 0
for ; i < 10; i++ {
fmt.Print("Hello World")
}

无限循环

for {
fmt.Print("Hello World")
}

for range:遍历数组、切片、字符串

s1 = "Hello World"
/*
i:索引
v:索引对应的值
*/
for i, v := range s1 {
fmt.Printf("%d $c", i, v)
}

switch和goto

s1 := 2
switch s1 {
case 1:
// do something
case 2:
// do something
case 3:
// do something
}

s := 1
if s == 1{
goto xx
}

xx: // xx标签
fmt.Print("Hello World")

运算符

复杂数据类型

数组

数组从声明时就必须确定大小,并且长度不可变

// var 数组名 [元素数量]元素类型
var arr [4]int

数组的初始化(如果不初始化,默认为0

// 根据初始值自动推断数组的长度是多少
var arr [...]int{1, 2, 3, 4, 5}
// 未赋值的自动为0
var arr[4]int{2, 3}

数组的遍历

for i, v := range arr {
fmt.Printf("%d %c", i, v)
}

多维数组

var arr [3][2]int

切片

slice:数组的长度是固定的,并且数组c长度属于类型的一部分,切片是一个拥有相同长度的可变的序列,是对数组的封装

// 切片的定义
var arr []int
// nil表示为空
fmt.Print(arr == nil)

切片的长度和容量

var arr []int
// 求长度,类似于C++中STL中的size
fmt.Print(len(arr))
// 求容量,类似于C++中STL的cap
fmt.Print(cap(arr))

由数组得到切片

var ar[...]{2,3,4,5,6,7,8}
s3 = ar[0: 4]

为切片添加元素

// append
var arr[]int{2,1,1,1}
arr := append(arr, 3)

复制切片

var arr[]int{2,3,4}
var ar[]int
copy(ar, arr)

指针

go不存在指针操作,只有两个符号

  • &:地址
  • *:取值

获取指针类型

n := 1
p := &n
fmt.Printf("%T\n", p) // *int

new:初始化一个指针

var s2 := new(int)

make:也是用于内存分配,不过是用于slice、map和chan的分配,返回后的可直接看作一个变量名

make(s1[]int, 10)

map

映射数据结构,基于哈希表

// map名称[key类型]value类型
var mm[int]int
mm[1] := 2
mm[2] := 3

用make动态分配内存

func main() {
var m = make(map[string]int, 10)
for i := 0; i < 10; i++ {
key := "ppa"
value := rand.Intn(100) // 生成0~99的随机数
m[key] := value
}
// 取出所有的key存入切片
var pp = make(arr[]string, 0, 10)
for i, v := range pp {
pp = append(pp, v)
}
// 对切片进行排序
sort.Strings(pp)
// 按照排序后的key遍历map
for _, key := range pp {
fmt.Println(key, map[key])
}
}

函数

/*
func 函数名(参数)(返回值){
函数体
}
*/
func sum(x int, y int)(ret int) {
return x + y
}
func main() {
s := sum(1, 2)
fmt.Printf("%d\n", s)
}

特殊写法

// 返回值只写类型
func sum(x int, y int) int {
return x + y
}
// 返回值写了名称但是return自动返回
func sum(x int, y int)(ret int) {
ret := x + y
return // 此时默认返回ret
}
// 类型简写
func sum(x, y int) int {
return x + y
}
// 多个返回值
func sum()(string, int) {
return "Hl", 2
}
// 可变长参数
func sum(x string, y ...int) {
// do something
}

defer

defer语句会将其后面跟随的语句进行延迟处理,在defer归属的函数即将返回时,将延迟处理的y语句按照defer定义的逆序进行执行(多用于资源释放

func sum() {
fmt.Print("Hello World") // 0
defer fmt.Print("Hello UNIX") // 3
defer fmt.Print("Hello Linux") // 2
fmt.Print("Hello Windows") // 1
}

函数类型和变量

函数也是可以作为一种类型存在,

func sum() {
fmt.Print("Hello World!")
}
func main() {
a := sum // 将函数赋值给变量a,此时a应该是什么类型?
}

函数也可以作为参数的类型

func x(f func()int) {
ret = f
ret()
}

函数也可以作为返回值

func x() func(x, y int)int {
ret := func(a, b int) int {
return x + y
}
return ret
}

匿名函数

var f1 = func(x, y int) {
return x + y
}

闭包

定义一个新的函数对原函数进行封装,一个函数包含了一个外部的变量的引用

func f1(x, y int) {
fmt.Print("Hello World")
}
func fm(x func(x, y int), x, y int) func() {
return func() {
x(x, y) // 去外部找到x和y
}
}
func main() {
ret := fm(1, 2)
ret()
}

当闭包的内部函数没有形参的时候,在外部去找

func f1(x, y int) {
fmt.Print("Hello World")
}
func fm(x func(x, y int), x, y int) func(int) {
return func(p int) {
x(x, y)
}
}
func main() {
ret := fm(1, 2)
ret(100)
}

结构体

自定义类型和类型别名

// 自定义类型
type myInt int
// 类型别名
type myInt = int

结构体

/*
type 类型名 struct {
字段名 字段类型
字段名 字段类型
字段名 字段类型
......
}
*/

type person struct {
name string
age int
hobby []string
}
func main() {
var p person
p.name = "lh"
p.age = 12
p.hobby = []string{"Hello World", "Hello Linux", "Hello UNIX"}
}

匿名结构体,不做概述

结构体指针和结构体初始化

type person struct {
name string
age int
}
func p(x person) {
p.name = "hl" // 修改的是副本,不是内存
}
func p1(x *person) {
p.name = "ha" // 修改的是内存
}
func main() {
var p person
p.name = "lh"
p.age = 12
f(p)
f(&p)
var d = new(person)
}

结构体初始化

// key-value
var ps = person {
name: "asd"
age: 12
}
// 列表
p4 = person{
"asd"
12
}
// 构造函数
func newPerson(name string, age int) person {
return person {
name: name
age: age
}
}

在GO中指针和普通值变量区别仅仅在于初始化和含义的不同,其他都是一样的(比如操作)

方法和接受者

go语言中的方法是作用于特定类型变量的函数,这种特殊变量叫做接受者(receiver)

/*
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}
*/
type person struct {
name string
age int
}
func (p person)wang() {
fmt.Printf("%s", p.name)
}

值接收者和指针接收者

// 值类型
func (p person)wang() {
fmt.Printf("%s", p.name)
}
// 指针类型,改内存
func (p *person)wang() {
fmt.Printf("%s", p.name)
}

假继承:不做概述

接口

接口是一种类型

编程会会遇到一种情况,我不管她是什么类型,我只关心能调用她的方法

type dog struct {}
type cat struct {}
type sp interface {
speak() // 有这个方法就是这个类型
}

func (d dog) speak() { // dog有speak方法
fmt.Print("Hello A")
}
func (c cat) speak() { // cat有speak方法
fmt.Print("Hello B")
}
func ap(d sp) {
d.speak()
}
func main() {
var d dog
var c cat
ap(d)
ap(c)
}

值接收者和指针接收者

接口都能存入 ,但是使用方法的时候必须使用特定的方法

type animal interface {
move()
eat(string)
}
type cat struct {
name string
feet int8
}
func (c cat)move() {
fmt.Print("Hello Mike")
}
func (c cat)eat(food string) {
fmt.Print("Hello Amy")
}
func main() {
var a1 animal

c1 := cat {"Tom", 12}
c2 := &cat {"dd", 13}
a1 = c1 // 将c1存入到接口中
a1 = c2 // 将c2存入到接口中
}

接口和类型关系

  • 多个类型实现一个接口
  • 一个类型实现多个接口
  • 接口嵌套

type person interface {
A
B
}
type A interface {
A()
}
type B interface {
B()
}

空接口

任何类型都可用

interface {}

空接口作为函数的参数,表示可以接收任何类型的参数

func a(p interface{})

空接口作为map的值

ma map[string]interface {}

包命名

package app
// 在GO语言导入包的时候会自动触发init函数的调用,其my参数也没有返回值
func init() {
fmt.Print("Hello World!")
}
// 包内的函数如果小写则表示只能在本包内使用
func Add(a, b int) int {
return a + b
}

包的导入

// 单包
import "app"
// 多包
import (
"app"
"bpp"
)

文件操作

打开和关闭文件

os .open()函数能够打开一个文件,返回士个File 和一个err 。对得到的文件实例调用close() 方法能够关闭文件。.

import "os"

// 打开文件
file, err := os.Open("path")
if err != nil {
fmt.Print(err)
return
}
// 关闭文件
file.Close()

读文件

var tmp = [128]byte
// 循环读取
for {
n, err := file.Read(tmp[:])
if err == io.EOF {
fmt.Print("读完了")
return
}
if err != nil {
fmt.Print(err)
return
}
// 读取了多少字节
fmt.Print(n)
// 打印内容
fmt.Print(tmp[: n])
if n < 128 {
return
}
}

文件写入

os .OpenFile() 函数能够以指定模式打开文件,从而实现文件写入相关功能。

模式

含义

os.O_WRONLY

只写

os.O_CREATE

创建文件

os.O_RDONLY

只读

os.O_RDWR

读写

os.O_TRUNC

清空

os.O_APPEND

追加

r:04,w:02,x:01

fileObj, err := os.OpenFile("./xx.txt", os.O_WRONLY|os.RDONLY, 0644)
if err != nil {
fmt.Print(err)
return
}
fileObj.Write([]byte("Hello World!\n"))
fileObj.WriteString("Hello Linux!")
fileObj.Close()

标准输入和输出

func io() {
var s string
fmt.Print("please input content")
fmt.Scanln(&s)
fmt.Printf("%s\n", s)
}

使用bufio:可以读入空格

import "io/bufio"

func use() {
var s string
// os.Stdin相当于是一个终端
reader := bufio.NewReader(os.Stdin)
s, _ = reader.ReadString('\n')
fmt.Printf("%s", s)
}

相同的也可以放在文件流中

file, err := os.Open("path")
if err != nil {
fmt.Print(err)
return
}
reader := bufio.NewReader(file)
for {
line, err = reader.ReadString('\n')
if err == EOF {
return
}
if err != nil {
fmt.Print(err)
return
}
fmt.Printf("%s", line)
}

内置包

time

time.Time类型表示时间。我们可以通过time . Now()|函数获取当前的时间对象,然后获取时间对象的年月日时分秒等信息。示例代码如下:

now := time.Now() // 获取当前时间
fmt.Printf("%v\n", now)

year := now.Year()
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
second := now.Second()
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)

时间戳

now := time.Now() // 获取当前时间
t1 := now.Unix()
t2 := now.UnixNano() // 纳秒数

// 使用time.Unix(a, 0)将时间戳转换成时间格式
timeObj = time.Unix(t1, 0)


举报

相关推荐

0 条评论