学习go语言一篇就够了(持续更新)
前言:写博客也写了差不多一年了,我更多的时候是记录自己学习的情况,有时也有自己工作上遇到的bug,自己有时候也比较迷茫,不知道怎么去写博文,我也很想别人跟我提提建议,但是有时候觉得写写博客还是很有成就感的,我有时候觉得快速的把知识点过一遍然后进行大量的练习和补充每个知识点的不足,让自己写的博文能更加完善些(关于这个博文是一套视频和两本连起来总结的,所有有时候会感觉知识点有点混乱)
学习方向
区块链研发工程师
Go服务器端/游戏软件工程师
golang分布式/云计算软件工程师
学习方法
先know how
,在know why
Golang的语言特点
注意事项
以"go" 为扩展名
执行入口是main()函数
严格区分大小写
每个语句后面不带分号
定义的变量和import的包如果没有使用到,代码不能编译通过
shift+tab整体向左移动(编辑器)
使用一个表达式形容Go语言: Go=C+Python
print()
println() //print+line
printf() //print+format
Sprintln()//获取字符串
Sprint()
Sprintf()
%T , 打印变量的数据类型
%d , 打印整数,十进制
%f , 打印浮点,小数
%t , 打印字符串
%s , 打印字符串
%v , 原样输出
%c , 打印对应的unicode字符
%p , 打印地址
变量的定义
var 变量 数据类型
变量名=赋值
缩写成一行
var 变量名 数据类型=赋值
类型推断
var 变量名=赋值
省略var
变量: =赋值
b:=2 //简短声明不支持全局变量
在同一区域同一数据类型内不断变化的
var num int //默认为0 跟js差不多 undefined
_
只写,不能读
常量
const 常量 数据类型=赋值
const 常量名=赋值
所有的字母大写
如果私有 前加小写字符c
一组常量中,如果某个常量没有初始值,那么默认和上一行一致
iota
:计数器 默认为0const(
e=iota
f
g
) //每当定义一个常量累加1
整型
int
uint
和操作系统有关
浮点
float32
单精度float64
双精度
字符串
一个字符byte
Go语言字符使用UTF-8 英文字符1个字节 汉字3个字节
字符串一旦赋值了,就不能在修改
反引号是直接输出``
布尔(bool)
只能取true false不能取0,1 占用一个字节
Go在不同类型的变量之间赋值是需要显式转换,也就是说Golang中数据类型不能自动转换
var i int32 = 100
var n1 float32 = float32(i)
var n2 int8 = int8(i)
var n3 int64 = int64(i)
fmt.Print("i=%v n1=%v n2=%v n3=%v", i, n1, n2, n3)
%v 需要转换的变量
基本数据类型 的默认值
基本类型转string类型
fmt.Sprintf
会返回转换后的字符串strconv.FormatFloat
strconv.FormatInt
strconv.formatbool
string类型转基本数据类型
strconv
ParseInt()
ParseFloat()
ParseBool()
ParseUint()
n1,_=strconv.ParseInt(str2,10,64)
f1,_=strconv.ParseFloat(str3,64)
算术运算符
- 对于除号"/" 只保留整数部分而舍弃小数部分
Golang的自增自减只能当作一个独立语言使用
例如
i++
i--
++和--只能写在变量的后面,不能写在变量的前面
go 语言明确不支持三元运算符
键盘输入语句
fmt.Scanln()
fmt.Scanf()
fmt.scanf
可以按照指定的格式输入fmt.Scanf("%s,%d,%f,%t",&name,&age,&sal,&ispass)
通过&变量保存数据
fmt.Scanln(&name)
if x>y {
fmt.Println("true")
}
if else if
/*希望函数内的变量能改变函数外的数值,可以传入变量的地址&
函数内以指针的方式操作变量*/
func test03(n1 *int) {
*n1=*n1+10
fmt.Println("test03 n1=",*n1)
}
func main(){
num:=20
test03(&num)
fmt.Println("main() num",num)
}
go函数不支持重载
自定义数据类型
type 自定义数据类型 数据类型
type myInt int
var num1 myInt
var num2 int
num1=400
num2=int(num1) //这里依然需要显示转换,go认为myInt和int两个类型
args
是slice
切片,通过args[index]
可以访问各个值
func sum(n1 int,args... int)int{
sum:=n1
for i:=0;i<len(args);i++{
sum+=args[i]//args[0] 表示取出args切片的第一个元素之
}
return sum
}
func main(){
res:=sum(1,2,3,4,5,5,6,6)
fmt.Println("res=",res)
}
每一个源文件都可以 包含一个init函数,init会在main函数前调用
执行顺序
bufio包
reader:=NewReader(os.Stuio)
reader.ReadLine()====>[]byte
reader.ReadString('\n')-->String
内置包
math包提供数学计算的函数
math.Abs()
go语言特有
fallthrough
穿透
当某个case匹配成功后执行,如果有fallthrough,那么后面紧邻的case不再匹配,直接执行
//math/rand包下
//时间
t1:=time.Now().Unix()
fmt.Println(t1)
//设置种子数
rand.Seed(t1) //设置获取随机数的种子数
num1:=rand.Intn(10) //[0,10)
fmt.Println(num1)
数组
var arr [4]int
var b=[4]int{1,2,3,4}
f:=[...] int{1,2,3,4,5}
len() 长度
cap() 容量
//因为数组是定长的容器,长度和容量是相同的
range 对数组 取数组的下标和value
for index,value :=range arr{
fmt.Println("下标是",index,"数值是",value)
}
for _,v :=range arr{
fmt.Println(v)
}
二维数组
arr:=[4][3]int{{1,2,3},{1,2,3},{1,2,3},{1,2,3}}
切片
切片slice
同数组类似,也叫做变长数组
是一个引用类型的容器,指向了一个底层数据
因为切片是引用数据的数据,直接拷贝的是地址
浅拷贝:拷贝的数据地址 copy()
深拷贝: 拷贝的数据本身
s2:=[]int{1,2,3,4}
内置函数
make()
s1:=make([] 类型 ,len,cap) 第一个参数:切片的类型,第二个参数:len,第三个参数容量,如果省略,默认跟第二个一样
----------------
s2:=make([] int,3)
s2=append(s2,1,2,3,4)
a[start:end] //包左不包右
当向切片添加数据时,如果没有超过容量,直接添加,如果超过容量,自动扩容(成倍增加)
/* 数组传递的是数据
切片传递的是地址*/
s1:=[] int{1,2,3,4,5}
fmt.Println(s1)
s2:=s1
fmt.Println(s2)
s2[0]=100
fmt.Println(s1)
fmt.Println("--------")
s3:=[5] int{1,2,3,4,5}
fmt.Println(s3)
s4:=s3
fmt.Println(s4)
s4[0]=100
fmt.Println(s4)
fmt.Println(s3)
copy copy(s1,s2) 把s2拷贝到s1,但是不会改变长度,能装多少装多少
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{6, 7, 8, 9}
copy(s1,s2)
fmt.Println(s1)
字符串操作
一个字节的切片
strings包下的字符串函数
strings.Contains() 是否包含指定的内容
strings.ContainsAny() 是否包含任意一个字符
Repeat 自己拼接自己count次
大小写转换 ToLower() ToUpper()
切割Split() SplitN()
Index IndexAnyLastIndex() LastIndexAny()
Replace(s,old,new,n)
Trim()
HasPerfix() 以xx前缀开头
HasSuffix() 以xx后缀结尾
查找
EqualFold不区分大小写的字符串比较
index 找不到返回-1
TrimSpace() 将字符串左边两边的空格去掉
Trim("元字符串",指定要去除的) 将指定的字符串左右两边空格去掉(有区别哦)
...
字符串遍历,同时处理有中文的问题
r:[]rune(str)
str:="hello被"
r:=[]rune(str)
for i:=0;i<len(r);i++{
fmt.Printf("%c\n",r[i])
}
字符串转整数
n,err=strconv.Atoi("12")
b:="65"
s2, _ :=strconv.Atoi(b)
fmt.Printf("%v",s2)
整数转字符串
str=strconv.Itoa(1234)
字符串 转[]byte:
var bytes=[]byte("hello go")
[]byte转字符串
str=string([]byte{'a','b','c'})
十进制转2,8,16进制
str=strconv.FormatInt(123,2)
//2->8,16
map, 映射
key ,value 也是一个容器,存储的无序键值对
key不重复,重复就覆盖
map声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用
类型
%T
m:=map[string]int{"one":1,"two":2}
m:=make(map[string]int)
nil 空
将map存进切片中
s1:=make([] map[string]string,0,3)通过key获取value,当key如果不存在的时候,我们会得到value的默认值
map1[key]=value,根据key获取map中对应的value
value,ok:=map[key]
如果键值对存在,value就是对应的数据,ok为true如果key不存在获取,获取的是 值的默认值,ok为false,默认key为0
value,ok:=map[key]
f ok{
fmt.Println("对应的数值是:",v1)
}else{
fmt.Println("操作的key不存在",vl)
}内置函数delete
- delete(map1,key)
sort排序
sort.Ints(key) 字符按照字符串的编码值排序
str="FKJKJFJdfjakfjakKSKJW"
map1 := make(map[byte]int)
for i := 0; i < len(str); i++ {
val, ok := map1[str[i]]
if ok {
val++
} else {
val = 1
}
map1[str[i]] = val
}
keys := make([]byte, 0, len(map1))
for k := range map1 {
keys = append(keys, k)
}
for _, k := range keys {
fmt.Printf("%c,%d\n", k, map1[k])
}
map1:=make(map[string]map[string]string)
//需要定义长度
map1["name"]=make(map[string]string,3)
map1["liming"]=make(map[string]string,3)
map1["name"]["name3"]="张三"
map1["name"]["name1"]="李四"
map1["name"]["name2"]="王五"
map1["liming"]["xiaoming1"]="小明"
map1["liming"]["xiaoming2"]="小红"
map1["liming"]["xiaoming3"]="小白"
for k,v :=range map1{
fmt.Println(k,v)
for k2,v2:=range v{
fmt.Println(k2,v2)
}
}
time
time.new 获取当前时间
格式化事件
fmt.Printf
fmt.SPrintf
now:=time.Now()
fmt.Printf("now=%v,now\n",now)
fmt.Printf("%d-%d-%d %d:%d:%d\n",now.Year(),now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second())
time.Format()
fmt.Printf(now.Format("2018-12-12 14:34:23))
Unix() 1970到现在的毫秒值
UnixNano 1970到现在的纳秒值
内置函数
len
new
异常处理
//使用defer+recover 来捕获异常
defer func() {
err := recover() //recover()内置函数,可以捕获到异常
if err != nil {
//说明捕获到错误
fmt.Println("err=", err)
}
}()
errors.New("错误说明") 会返回一个err类型的值表示一个错误
//自定义错误
// 定义一个函数,用于求矩形的面积
func getArea(wid,len float64)(float64,error){
errorMsg:=""
if wid<=0{
errorMsg="宽度为负数"
}
if len<0{
if errorMsg==""{
errorMsg="长度为负数"
}else{
errorMsg+=",长度也为负数"
}
}
if errorMsg !=""{
return 0,&errorRect{errorMsg,wid,len}
}
area:=wid*len
return area,nil
}
函数
go语言支持函数式编程+面向对象
- 函数:独立功能,直接调用
- 方法:对象的功能,对象来调用
可变参数: 参数名...
函数中,可变参数想当于切片
位置参数>可变参数 (顺序)
写返回值的时候,必须在函数上声明返回值的类型
函数式编程
一个函数可以作为另一个函数的参数或返回值
递归函数
自己调用自己
func getgui(n int) int{
if n==1||n==2{
return 1
}
return getgui(n-1)+getgui(n-2)
}
匿名函数
func(a,b int){
fmt.Println(a,b)
}(1,2)
高阶函数(回调函数)
根据go语言函数的数据类型的特点,可以将函数作为另一个函数的参数
func add(a,b int) int{
return a+b
}
func oper(m,n int,fun func(int,int)int)int{
res:=fun(m,n)
return res
}
func main() {
fmt.Println(
oper(10,20,add))
}
闭包
引用外部变量的匿名函数
支持将函数作为另一个函数的返回值
func f(i int) func() int{
return func() int{
i++
return i
}
}
func main() {
str:=f(10)
fmt.Println(str())
fmt.Println(str())
}
-----------------------------
func ExFunc(n int) func () {
sum:=n
a:=func(){
fmt.Println(sum+1)
}
return a
}
func main() {
myFunc:=ExFunc(10)
myFunc()
}
函数的defer(延时机制)
在执行到defer是,暂时不执行,会将defer后面的压入独立的栈,按照先入后出的方式出栈,执行
先defer再return
获取变量的地址,用&
获取指针类型所指向的值*
fmt.Println(&num)
var ptr *int=&num
值类型,都有对应的指针类型 新式为*数据类型
结构体
//定义一个类,就是定义一个结构体
//类的定义,字段属性,行为方法
type 结构体名称 struct{
name type
age int
}
//定义结构体变量
var p1 结构体名称
p2:=Person{"mary",20}
p6:=new(Person)
var p1 Person
p1.Age=10
p1.Name="小明"
var p2 *Person=&p1
fmt.Println((*p2).Age)
注意不能*p2.Age写,因为.的优先级比* 高
// 实现结构体的浅拷贝
d4:=new(dog)
d4.color="黄色"
d4.age=2
d4.kind="中华田园犬"
fmt.Println(d4)
d5:=d4
d5.kind="张三"
fmt.Println(d5,d4)
d6:=&d1//*dog
d6.kind="金毛"
fmt.Println(d6,d1)
//匿名结构体:没有名字的结构体,在创建匿名结构体,同时创建对象
p1:=struct {
name string
age int
}{
name: "zhangsan",
age: 30,
}
//匿名字段
type student struct{
string
int//匿名字段(不能有重复字段)
}
s1:=student{"zhgsan",12}
fmt.Println(s1.string,s1.int)
type Book struct{
bookName string
price float64
auther string
}
//嵌套struct的名称冲突
有以下两个名称冲突的规则(报错)
* 外部struct覆盖内部struct的同名字段,同名方法(1)
* 同级别的struct出现同名字段,方法将报错(2)
type A struct{
a int
b int
}
type B struct{
b int
c string
d string
}
type C struct {
A //继承
B
a string
c string
}
(1) C.a和C.c分别覆盖A.a和B.c
(2) A.b和B.b
为什么呢? 继承的"提升字段"
//结构体嵌套
//模拟面向对象:聚合关系
//一个类作为另一个类的属性
//定义一个书的结构体
type Book struct{
bookName string
price float64
auther string
}
//定义一个人的结构体
type Person struct{
name string
age int
book Book //聚合
}
func main() {
p3:=Person{
name:"Jerry",
age:26,
book:Book{
bookName:"Go语言是怎么练成的",
price:55.0,
auther:"张三",
},
}
fmt.Println(p3.book.auther,p3.book.price,p3.book.auther)
p4:=Person{"李晓华",20,Book{"四万个为什么",44.8,"张三"}}
fmt.Println(p4.book.auther,p4.book.price,p4.book.auther)
}
- struct 的数据类型:值类型:默认深拷贝
- 如果结构体的字段类型是:指针,slice,和map的零值都是nil,还没有分配空间
- 如果需要使用这样的字段 ,需要先make,才能使用
- 结构体是值类型
方法
type Person struct{
name string
age int
}
type Student struct {
Person
school string
}
//方法
func (p Person) eat(){
fmt.Println("父类的方法,吃我我头")
}
func (s Student) study(){
fmt.Println("子类的方法..")
}
func (s Student) eat(){
fmt.Println("子类重写父类的方法")
}
多态继承
接口(interface
):功能的描述的集合
- 定义有哪些功能
接口的意义
- 解耦合:程序和程序之间的关联程度,降低耦合性
- 继承关系:增加耦合
注意点:
- 当需要接口类型的对象时,那么可以使用任意实现类对象代替
- 接口对象不能访问实现类的属性
/* 多态*/
//定义一个接口
type Shape interface{
peri() float64 //周长
area() float64 //面积
}
//定义实现类:三角形
type Triangle struct {
a,b,c float64//三个边
}
func (t Triangle)peri() float64{
return t.a+t.b+t.c//周长
}
func (t Triangle)area() float64{
p:=t.peri()
s:=math.Sqrt(p*(p-t.a)*(p-t.b)*(p-t.c)) //面积
return s
}
type Circle struct {
radius float64//半径
}
func (c Circle)peri()float64{
return c.radius*2*math.Pi //面积
}
func (c Circle)area()float64{
return math.Pow(c.radius,2)*math.Pi
}
func teshShape(s Shape) {
fmt.Println("周长",s.peri(),"面积",s.area())
}
//转型
func getType(s Shape) {
/* 方法一:instance,ok:=接口对象.(实际类型)
如果该接口对象是对应的实际类型,那么instance就是转型之后对象
*/
ins,ok:=s.(Triangle)
if ok{
fmt.Println("是三角形",ins.a,ins.b,ins.c)
}else if ins,ok:=s.(Circle);ok{
fmt.Println("是圆形,半径是:",ins.radius)
}
}
//2 转型(向下转型)
func getType2(s Shape) {
/*方法二:接口对象.(type),配合switch和case语句使用*/
switch ins := s.(type) {
case Triangle:
fmt.Println("三角形", ins.a, ins.b, ins.c)
case Circle:
fmt.Println("圆形", ins.radius)
//case int:
// fmt.Println("整型数据...")
}
}
func main() {
/*
多态:一个事物的多种形态
go语言:通过接口模拟多态性
一个实现类的对象:
看作是一个实现类类型:能够访问实现类中的方法和属性
还可以看作是对应接口类型:只能够访问接口中定义的方法
用法一:一个函数如果接受接口类型作为参数,那么实际上可以传入接口的任意实现类对象作为参数
*/
t1:=Triangle{3,4,5}
fmt.Println(t1.peri())
fmt.Println(t1.area())
fmt.Println(t1.a,t1.b,t1.c)
var s1 Shape
s1=t1
fmt.Println(s1.peri())
fmt.Println(s1.area())
var c1 Circle
c1=Circle{4}
fmt.Println(c1.peri())
fmt.Println(c1.area())
fmt.Println(c1.radius)
var s2 Shape=Circle{5}
fmt.Println(s2.area(),s2.peri())
//定义一个接口类型的数组
arr:=[4]Shape{t1,s1,c1,s2}
fmt.Println(arr)
//接口类型的对象-->对应实现类类型
getType(c1)
}
空接口
也是一个接口,但是该接口中没有任何方法
所有可以将任意类型作为该接口的实现
//定义一个map:string作为key,任意类型作为value
map1:=make(map[string]interface{})
map1["name"]="王二狗"
map1["age"]=12
//空接口
type A interface {}
var a1 A=Cata{"花猫",1}
var a2 A=Persona{"王二狗","男性"}
练习1
/*
三维坐标,求两点的距离
*/
type Point struct{
x,y,z float64
}
func (p Point) PrintInfo(){
fmt.Println(p.x,p.y,p.z)
}
func (p Point) getDisance3(p2 Point) float64{
dis:=math.Sqrt(math.Pow(p.x-p2.x,2)+math.Pow(p.y-p2.y,2)+math.Pow(p.z-p2.z,2))
return dis
}
func main() {
p1:=Point{1,2,4}
p2:=Point{0,0,0}
p1.PrintInfo()
p2.PrintInfo()
fmt.Println(p1.getDisance3(p2))
}
学习go语言一篇就够了(持续更新)的更多相关文章
- 《ElasticSearch入门》一篇管够,持续更新
一.顾名思义: Elastic:灵活的:Search:搜索引擎 二.官方简介: Elasticsearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTf ...
- 《利用Hyper-V搭建虚拟机》一篇管够,持续更新
开门见山:win10+Hyper-V+ContOS7.X 万物皆有目的:没钱买云服务器,但平时在家想持续学习,可以考虑在自己windows上搭建一台虚拟机,然后装上Linux,调试通网络进行开发. 涉 ...
- C++入职学习篇--代码规范(持续更新)
C++入职学习篇--代码规范(持续更新) 一.头文件规范 在头文件中大家一般会定义宏.引入库函数.声明.定义全局变量等,在设计时最后进行分类,代码示范(自己瞎琢磨的,请多多指点): #ifndef T ...
- python3.4学习笔记(六) 常用快捷键使用技巧,持续更新
python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...
- 跟我学SpringCloud | 终篇:文章汇总(持续更新)
SpringCloud系列教程 | 终篇:文章汇总(持续更新) 我为什么这些文章?一是巩固自己的知识,二是希望有更加开放和与人分享的心态,三是接受各位大神的批评指教,有任何问题可以联系我: inwsy ...
- Python语言上机题实现方法(持续更新...)
Python语言上机题实现方法(持续更新...) 1.[字符串循环左移]给定一个字符串S,要求把S的前k个字符移动到S的尾部,如把字符串"abcdef"前面的2个字符'a'.'b' ...
- 学习Hibernate5这一篇就够了
配套资料,免费下载 链接:https://pan.baidu.com/s/1i_RXtOyN1e4MMph6V7ZF-g 提取码:8dw6 复制这段内容后打开百度网盘手机App,操作更方便哦 第一章 ...
- 学习MySQL这一篇就够了
MySQL 第一章 数据库概述 1.1.数据库的好处 将数据持久化到本地 提供结构化查询功能 1.2.数据库的常见概念 DB:数据库,存储数据的仓库 DBS:数据库管理系统,又称为数据库软件或者数据库 ...
- 学习JDBC这一篇就够了
配套资料,免费下载 链接: https://pan.baidu.com/s/1CKiwCbQV4FGg_4YMQoebkg 提取码: 7cn3 复制这段内容后打开百度网盘手机App,操作更方便哦 第一 ...
随机推荐
- python - socketserver 模块应用
server端: import socketserver import subprocess import json import struct class MyTCPHandler(socketse ...
- Junit的Assert用法
package junit.framework; /** * A set of assert methods. Messages are only displayed when an assert f ...
- 为什么用pycharm在同目录下import,pycharm会报错,但是实际可以运行?
问题已经找到了,pycharm不会将当前文件目录自动加入自己的sourse_path.右键make_directory as-->sources path将当前工作的文件夹加入source_pa ...
- Linux的记事本 Vi和Vim
⒈Vi和Vim的三种模式 ①正常模式 在正常模式下可以使用快捷键 默认进入的是正常模式 ②编辑模式(插入模式) 在该模式下可以输入内容 按下I,i,O,o,A,a,R,r等任何一个字母之后才可以进入该 ...
- ES系列三、基本知识准备
一.基础概念 1.索引 索引(index)是elasticsearch的一个逻辑存储,可以理解为关系型数据库中的数据库,es可以把索引数据存放到一台服务器上,也可以sharding后存到多台服务器上, ...
- Web 中调用FreeSWITCH的Portal GUI配置记录
具体设定步骤: ①加载 mod_xml_rpc 模块:load mod_xml_rpc 若想让该模块在FreeSWITCH启动时而自动加载,在conf/autoload_configs/modules ...
- 转载:《RESTful API 设计指南》 阮一峰
原文:http://www.ruanyifeng.com/blog/2014/05/restful_api 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面 ...
- sklearn 岭回归
可以理解的原理描述: [机器学习]岭回归(L2正则) 最小二乘法与岭回归的介绍与对比 多重共线性的解决方法之——岭回归与LASSO
- vue及webpack在项目中的一些优化
传送:https://www.haorooms.com/post/vue_webpack_youhua
- win7 X64系统上 PL/SQL不能识别Oracle实例
电脑系统为Win7 64位,安装的PLSql为64位,安装的Oracle客户端为运行时类型的,应该为32位客户端 电脑上之前安装的32位toad可以识别Oracle实例 在系统添加了oracle_ho ...