0
点赞
收藏
分享

微信扫一扫

Go基础--笔记

Go语言基础部分学习笔记:

(系统不支持插入Go代码 下面插入的代码选用的格式是C++......)

以下内容更多的并非解释相关知识是什么意思,而是给有过其他语言基础的人看看Go语言的语法格式,如何快速使用Go


首先是学任何一个语言都会首先去做的事,HelloWorld:

package main

import "fmt"

// 行注释
/*
块注释
*/
// 快速注释 ctrl + /

func main() {
// print
fmt.Println("Hello World")
}

变量部分:

和大部分语言一样,Go支持整形、浮点型、布尔类型、字符串类型,不过需要注意的是Go定义变量的方式

// 定义
// 格式:var 变量名 变量类型
var a int = 10
var b int
b = a// 赋值
// 自动推导变量类型
PI := 3.1415

// 声明多个变量并赋值
c, d := 1, 2

字符和字符串:

package main

import "fmt"

func main() {
var a byte = 'a'
var b string = "a"
fmt.Println(a, b)

str := "123456789"
// len() 系统函数 计算字符串长度
length := len(str)
fmt.Println(length)

str1 := "哈哈哈哈"
fmt.Println(len(str1))// 在Go中一个汉字等于3个字符 为了和Linux进行统一处理

常量的使用:

// 常量存储在数据区 变量存储在栈中
const a int = 10
fmt.Println(a)

怎么用输入输出:

可以看一下包fmt的文档,这里仅仅放一个例子

// 格式输入
var a int
// & 取地址
fmt.Scan(&a)
// %p 占位符 表示输出一个数据对应的内存地址
fmt.Printf("%p", &a)

运算符:

和大部分语言一样,包括算术运算符、关系运算符、逻辑运算符

// + - * / %
// ++ -- 自增 自减只有放在变量后面的形式 没有放在前面的
a := 10
a++
fmt.Println(a)
a--
fmt.Println(a)
b := 3
c := a / b//整型相除仍然是整型
fmt.Println(c)
// 赋值运算符
// = += -= /= *=
// 逻辑运算符
// ! && ||
// 关系运算符
// > < == != >= <=

流程控制:

包括if else、switch、循环只有for

func main() {
// 选择
// 注意格式 可嵌套
age := 17
if age < 18 {
fmt.Println("未成年")
} else if age >= 18 && age < 35 {// 注意 此处要写在同一行
fmt.Println("青年")
} else {// 注意 此处要写在同一行
fmt.Println("成年")
}

// switch
// 通过值进行选择
// switch中不能用浮点型数据 浮点型数据是一个约等于的数据
var w int
fmt.Scan(&w)
switch w {
case 1:
fmt.Println("星期一")
fallthrough// 让switch执行下一个分支的代码 如果不写执行到下一个分支就会自动停止 这个程序会在输入 1 的时候会输出 星期一 星期二
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
case 4:
fmt.Println("星期四")
case 5:
fmt.Println("星期五")
case 6:
fmt.Println("星期六")
case 7:
fmt.Println("星期日")
default:
fmt.Println("error")
}

// 循环结构
// go语言中只有一种循环结构 for循环
var i int
for i = 1; i < 10; i++ {
fmt.Println(i)
}

for j := 1; j < 10; j++ {
fmt.Println(j)
}

for j := 1; j < 10; j++ {
if j == 1 {
continue
}
fmt.Println(j)
}

for ; ; {// 死循环
break// 跳出
}
for{// 死循环另一种写法
break// 跳出
}
}

函数的定义与使用:

函数中变量的作用域、传参等就不做介绍

package main

import "fmt"

func test() {
fmt.Println("asdasd")
}

func test2(a int, b int) {
fmt.Println(a + b)
}

func test3(a int, b int) (sum int) {
sum = a + b
return
}
// type 可以定义函数类型
// type 可以为已存在的类型起别名
type FUNCTYPE func()
type FUNCTEST func(int, int)
type FUNCDEM func(int, int)int

func main() {
// 定义函数类型变量
var f FUNCTYPE
f = test
// 通过函数变量调用函数
f()

var f1 FUNCTEST
f1 = test2
f1(1, 2)

var f2 FUNCDEM
f2 = test3
_ = f2(1, 2)
}

匿名函数:

package main

import "fmt"

func main() {
a, b := 1, 2
// 匿名函数
// 定义并调用
//func (a int, b int) {
// fmt.Println(a + b)
//}(a, b)
f := func (a int, b int) {
fmt.Println(a + b)
}
f(a, b)

f1 := func (a int, b int) int {
return a + b
}(a, b)
fmt.Println(f1)
}

切片(或者说数组)的使用:

注意不要以为和Python的切片是一个意思,Go中的切片截取可以看作Python中的数组切片

package main

import "fmt"

// 切片作为函数参数
func test(s []int) {
s[0] = 88// 切片传递地址 源切片数据也会被改变
fmt.Println(s)
}

func main() {
// 数组定义 var 数组名 [元素个数]数据类型
// 切片定义 var 切片名 []数据类型

//var s []int
//fmt.Println(s)

// 自动推导类型创建切片
s := make([]int, 5)// 设置长度为5
s[0] = 1
s[1] = 2

//s[6] = 7// error 越界
// 使用append添加元素
fmt.Println(len(s))
s = append(s, 6, 7 , 8, 9)
fmt.Println(len(s))
fmt.Println(s)
// 查看容量
fmt.Println(cap(s))

// go的切片不是python的切片 可以看作C++的vector

// 推荐使用切片而不是数组

// 切片的截取 类似于python的切片
fmt.Println(s[2:])
fmt.Println(s[:4])
fmt.Println(s[2:4])
fmt.Println(s[0:2:4])// low = 0 height = 2 max = 4 cap = max - low

slice := s[2:4]// 切片数据仍然指向原始的s 修改slice的话s也会被修改
slice[0] = 9
slice[1] = 9
fmt.Println(slice)
fmt.Println(s)

s2 := make([]int, len(s))
copy(s2, s)// 拷贝操作 深拷贝 s2需要有足够的空间存放拷贝过来的数据
s2[0] = 100
fmt.Println(s)
fmt.Println(s2)
// 也可因copy切片的截取部分

test(s)
fmt.Println(s)
}

map的使用:

package main

import "fmt"

// map作为函数参数 是地址传递
func test(m map[int]string) {
m[1] = "AAAAAA"
}

func main() {
// map key 必须是基本数据类型
//var m map[int]string
m := make(map[int]string, 1)// map自动扩容
fmt.Println(m)
m[1] = "asdasd"
m[2] = "safasd"
m[9] = "asfkasd"
fmt.Println(m)
fmt.Println(m[2])

for k, v := range m {
fmt.Println(k, v)
}

// 判断是否存在key
v1, ok1 := m[1]
v5, ok5 := m[5]

if ok1 {
fmt.Println(v1)
} else {
fmt.Println("key 1 not existed")
}

if ok5 {
fmt.Println(v5)
} else {
fmt.Println("key 5 not existed")
}

// 删除map中的元素

fmt.Println(m)
delete(m, 1)
// delete删除map元素时 表示的时若可key存在就删除 不存在也不会报错
delete(m, 5)
fmt.Println(m)

test(m)

fmt.Println(m)
}

结构体的定义和使用:

Go中的结构体可以看作C++的类,而不是C中仅有数据成员的结构体

package main

import (
"fmt"
)

func test(s student) {
fmt.Println(s)
}

type student struct {
id int
age int
sex string
}

func main() {
var s student
s.id = 101
s.age = 12
s.sex = "man"

fmt.Println(s)

var s2 student = student{102, 13, "male"}
s3 := student{103, 14, "man"}
fmt.Println(s2, s3)

s4 := s
fmt.Println(s4)

// 结构体的比较
// !=
// ==

// 结构体切片
//var ss []student
ss := make([]student, 10)

ss = append(ss, student{104, 11, "man"})
fmt.Println(ss)

m := make(map[int]student)
m[1] = s
m[2] = s2
fmt.Println(m)
}

指针:

package main

import "fmt"

// 指针作为函数参数
func test(p *int) {
*p = 99
fmt.Println(*p)
}

// 切片指针作为函数参数
func test2(p *[]int) {
*p = append(*p, 999, 999)
}

type student struct {
id int
name string
}

func main() {
var a int = 10
// 定义整形指针变量 指向a的地址
// 与C++类似
var pa *int = &a
fmt.Println(pa)
*pa = 20
fmt.Println(a)

// 为指针变量创建一块内存空间
var p1 *int
// 堆
p1 = new(int)
fmt.Println(*p1)
fmt.Println(p1)

test(&a)
test(p1)
fmt.Println(a)
fmt.Println(*p1)

// 数组指针
var arr [5]int = [5]int{1, 2, 3, 4, 5}
fmt.Println(arr)
fmt.Printf("%p\n", &arr)

// 数组指针定义时给出的数组大小需要和赋值给他的数组大小一样
// var parr *[5]int
// parr = &arr
parr := &arr
fmt.Println(*parr)
fmt.Println(parr)
fmt.Printf("%T\n", parr)

// 切片指针
var slice []int = []int{1, 2, 3, 4, 5}
ppslice := &slice
fmt.Println(slice)
fmt.Println(*ppslice)
fmt.Println(ppslice)// 二级指针
fmt.Printf("%T\n", ppslice)
fmt.Println(*ppslice)
// 切片名本身就是一个地址
(*ppslice)[0] = 9
fmt.Println(slice)
// ppslice[0] = 9 error 和数组指针不同
test2(ppslice)
fmt.Println(slice)

// 用new创建切片指针空间
var p3 *[]int
fmt.Printf("%p\n", p3)
p3 = new([]int)
fmt.Printf("%p\n", p3)
*p3 = append(*p3, 1, 2, 3, 4, 5)
for i := 0; i < len(*p3); i++ {
fmt.Println((*p3)[i])
}

// 指针数组 指针切片
a, b, c := 1, 2, 3
var pointarr [3]*int = [3]*int{&a, &b, &c}
*pointarr[0] = 99
fmt.Println(a)

// 指针切片
var pointslice []*int
pointslice = append(pointslice, &a, &b, &c)
*pointslice[2] = 99
fmt.Println(c)

// 结构体指针
var st student = student{101, "bob"}
fmt.Println(st)
var pstudent *student = &st
pstudent.id = 102
pstudent.name = "marrys"
fmt.Println(st)

// 多级指针
x := 10
px := &x
ppx := &px

}

同名字段个匿名字段:

package main

import "fmt"

type person struct {
name string
age int
sex string
}

// 结构体嵌套
type student struct {
person// 匿名字段
id int
score int
name string// 同名字段
}

type student2 struct {
*person// 指针匿名字段
id int
score int
name string// 同名字段
}

func main() {
// var stu student = student{person{...}, ...}
var stu student
stu.id = 101
stu.score = 100
stu.name = "nana"
stu.person.name = "lala"
stu.person.age = 18
stu.sex = "female"
fmt.Println(stu)

var stu2 student2
//stu2.person.name = "kaka"// invalid memory address or nil pointer dereference
stu2.person = new(person)
stu2.name = "baba"
stu2.person.name = "kaka"
fmt.Println(stu2)
}

多重继承:

package main

import "fmt"

type test1 struct {
name string
id int
}

type test2 struct {
test1
sex string
age int
}

type test3 struct {
test2
score int
}

type test4 struct {
test1
test2
score int
}

func main() {
var s test3
s.name = "asda"
s.age = 19
s.score = 1213
fmt.Println(s)
}

结构体的方法的定义和使用:

可以看作类的成员函数

package main

import "fmt"

//func add(a, b int) int {
// return a + b
//}

// 起别名
type Int int

// 方法
// func (方法接收者)方法名(参数列表)返回值类型
func (a Int) add (b Int) Int {
return a + b
}

type student struct {
name string
age int
sex string
}

// 为结构体定义别名
func (stu student) PrintInfo () {
fmt.Println(stu.sex)
fmt.Println(stu.name)
fmt.Println(stu.age)
}

func (stu *student) Rename () {
stu.name = "asdasdasd"
}

// 方法的继承
type test struct {
student
index int
}

// 方法的重写
func (t test) PrintInfo () {
t.student.PrintInfo()
fmt.Println(t.index)
}

// 方法类型和方法的值

func main() {
// 根据数据类型绑定方法
var a Int = 1
var b Int = 3
fmt.Println(a.add(b))

stu := student{"sdsad", 10, "male"}
stu.PrintInfo()
stu.Rename()
fmt.Println(stu)

var t test
t.index = 101
t.age = 19
t.sex = "male"
t.name = "Bbb"
t.student.PrintInfo()
t.PrintInfo()
fmt.Println(t)
t.Rename()
fmt.Println(t)

f1 := t.PrintInfo
f2 := t.student.PrintInfo
fmt.Printf("%T\n", f1)
fmt.Printf("%T\n", f2)

f1()
f2()

}

接口的定义和使用:

package main

import "fmt"

type person struct {
name string
sex string
age int
}

type student struct {
person
score int
}

type teacher struct {
person
subject string
}


func (s *student)SayHello(){
fmt.Printf("name: %s, score: %d\n", s.name, s.score)
}

func (t *teacher)SayHello(){
fmt.Printf("name: %s, subject: %s\n", t.name, t.subject)
}

// 接口的定义
// 接口定义了规则 方法实现了规则
type TestInterface interface {
// 方法的声明 没有具体实现
// 接口中定义的方法必须全部有具体的实现
SayHello()
}

// 多态
type Person interface {
SayHello()
}

// 多态实现
// 多态是将接口类型作为函数参数
func SayHello(p Person){
p.SayHello()
}

// 接口的继承
type Speaker interface {
Person
Sing(string)
}

func (s *student)Sing(name string){
fmt.Printf("Sing %s Name %s\n", name, s.name)
}

func main () {
var stu student = student{ person{"Bob", "male", 18}, 99 }
var tea teacher = teacher{ person{"marry", "male", 28}, "Math" }

stu.SayHello()
tea.SayHello()

// 定义接口类型
var h TestInterface
h = &stu
h.SayHello()

h = &tea
h.SayHello()

var p Person

// 接口
p = &student{ person{"Bob", "male", 18}, 99 }
// 多态
SayHello(p)

p = &teacher{ person{"marry", "male", 28}, "Math" }
SayHello(p)

var s Speaker
s = &stu
s.SayHello()
s.Sing("lalala")

// 接口的转换
// 将超集转换为子集
p = s
p.SayHello()

// 不允许子集转换为超集
// s = p // error

// 空接口
var i interface{}
i = 10
fmt.Println(i)
i = "Hello"
fmt.Println(i)

// 类型断言
if data, ok := i.(string); ok {
fmt.Println("string ", data)
}
}

异常处理:

package main

import (
"fmt"
"errors"
)

func test(a int, b int) (value int, err error) {
//return a / b
if b == 0 {
err = errors.New("0不能作为除数")
return
} else {
value = a / b
return
}
}

func test2(a int, b int) (value int) {
value = a / b
return value
}

func test3() {
fmt.Println("test3")
// 调用panic程序自动终止
panic("test3 panic")
}

func main() {
value, err := test(10, 0)// 注意此处问题 0不能作为除数
if err != nil {
fmt.Println(err)
} else {
fmt.Println(value)
}
value1, err1 := test(10, 2)// 注意此处问题 0不能作为除数
if err1 != nil {
fmt.Println(err1)
} else {
fmt.Println(value1)
}

// panic异常处理
//value2 := test2(10, 0)// panic: runtime error:
//fmt.Println(value2)

//
//test3()

// 延迟调用
// defer 在程序运行结束后再运行 先defer的后调用
fmt.Println("Hello 1")
defer fmt.Println("Hello 2")
fmt.Println("Hello 3")
defer fmt.Println("Hello 4")
fmt.Println("Hello 5")

a, b := 10, 20
f := func(a int, b int) {
fmt.Println(a)
fmt.Println(b)
}
f2 := func() {
fmt.Println(a)
fmt.Println(b)
}
// 注意变量作用域
defer f(a, b)// 输出10, 20
defer f2()// 输出100, 200

a, b = 100, 200

fmt.Println("end...")
}

文件相关的操作:

package main

import (
"fmt"
"os"
"io"
//"bufio"
)

func main123() {
// 创建文件 如果指定路径文件存在 则覆盖 否则创建
fp, err := os.Create("../data/a.txt")
// 文件创建失败
if err != nil {
fmt.Println("file create error")
return
}

fmt.Println("file create successful")

// 延迟调用 关闭文件
// 占用内存和缓冲区
// 文件打开上限
defer fp.Close()

// 写入文件
fp.WriteString("hello\n")

// 返回写入字符数
n, _ := fp.WriteString("world\n")
fmt.Println(n)
// 一个汉字代表三个字符 换行算一个
n, _ = fp.WriteString("你好\n")
fmt.Println(n)

// 写入字符切片
b := []byte{'a', 'b', 'c', 'd'}
// 使用Write写入数据
fp.Write(b)

// 将字符串转为字符切片写入文件
str := "HashSort"
// 字符串和字符切片允许转换
c := []byte(str)
fp.Write(c)
}

func main124() {
// 打开文件
// OpenFile只能做打开操作 不能创建文件
fp, err := os.OpenFile("../data/a.txt", os.O_RDWR, 6)

if err != nil {
fmt.Println("OpenFile error")
return
}
defer fp.Close()

// 获取文件字符个数
n, _ := fp.Seek(0, io.SeekEnd)
fmt.Println(n)

b := []byte("HELLO\n")
// 使用WriteAt进行指定位置插入数据时会依次覆盖
fp.WriteAt(b, 0)// 0表示offset 表示当前位置
}

func main() {
// 只读方式打开文件
fp, err := os.Open("../data/a.txt")
// 文件打开失败的原因 文件不存在 没有打开权限 打开的文件数目达到上限
if err != nil {
fmt.Println("Open error")
return
}
defer fp.Close()

//b := make([]byte, 1024)

// 读取文件
//fp.Read(b)
//fmt.Println(string(b))

// 创建切片缓冲区
//r := bufio.NewReader(fp)
// 读取一行内容
//b, _ := r.ReadBytes('\n')
//fmt.Println(string(b))

b := make([]byte, 10)

for {
n, err := fp.Read(b)
if err != nil {
if err == io.EOF {
break
}
}
fmt.Print(string(b[:n]))
}
}

字符串的操作:

包括判断子串是否存在、字符串拼接、查找子串位置等

package main

import (
"fmt"
"strings"
"strconv"
)

func main() {
str := "aaabbbcccddd"
// 判断是否存在子串
value := strings.Contains(str, "aaa")

if value {
fmt.Println("str存在aaa")
} else {
fmt.Println("str不存在aaa")
}

fmt.Println(value)

s := []string{"aaa", "bbb", "ccc"}
// 字符串拼接
str = strings.Join(s, "-")
fmt.Println(str)

str = "123456789"
// 查找子串位置 返回下标值 未找到返回-1
idx1 := strings.Index(str, "456")
idx2 := strings.Index(str, "436")
fmt.Println(idx1)
fmt.Println(idx2)

// 重复字符串
str = "ABCD"
res := strings.Repeat(str, 3)
fmt.Println(res)

// 字符串转换
// 将其他类型转换成字符串
str = strconv.FormatBool(false)
fmt.Println(str)

str = strconv.FormatInt(123, 10)// 十进制数123
fmt.Println(str)

str = strconv.Itoa(12445)
fmt.Println(str)

str = strconv.FormatFloat(1.254, 'f', 5, 64)// 浮点数 1.254 小数位5 64位
fmt.Println(str)

// 字符串转换为其他类型
str = "false"
// 忽略错误信息
//b, _ := strconv.ParseBool(str)
b, err := strconv.ParseBool(str)
//fmt.Println(b)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(b)
}

// 将字符串转化为整形
str = "1010101"
//a, _ := strconv.ParseInt(str, 2, 64)// 将2进制64位整数str转为10进制数
a, _ := strconv.ParseInt(str, 10, 64)// 将10进制64位整数str转为10进制数
fmt.Println(a)

str = "12.35545"
d, _ := strconv.ParseFloat(str, 64)
fmt.Println(d)

// Append
e := make([]byte, 0, 1024)
// 将bool类型放在指定切片中
e = strconv.AppendBool(e, false)
e = strconv.AppendInt(e, 123, 10)
e = strconv.AppendFloat(e, 1.234, 'f', 5, 64)
fmt.Println(string(e))

}

转载请注明出处



举报

相关推荐

0 条评论