go笔记

时间和日期函数

  1. 时间和日期相关函数,需要导入time包
  2. 获取当前时间 now := time.Now()
  3. 如何获取到其他的日期信息 now.Format()
  4. fmt.Printf(’%d-%d-%d %d:%d:%d’, now.Year(),now.Month(),…)
  5. 格式化日期时间的第二种方式
    fmt.Printf(now.Format(“2006-01-02 15:04:05”))
    fmt.Printf(now.Format(“2006-01-02”))
    fmt.Printf(now.Format(“15:04:05”))
  6. 时间的常量
    const(
    Nanosecond Duration =1 //纳秒
    Microsecond = 1000 * Mi
    Mill

常量的作用:在程序中可用于获取指定时间单位的时间,比如想得到100毫秒
7. time.Sleep()
8. 获取当前Unix时间戳和unixnano时间戳 (可以获取随机的数字)
9. fmt.Printf(’%v’,now.Unix(),now.UnixNano())

golang设计者为了编程方便,提供了一些函数,这些函数可以直接使用—内置函数

  1. len
  2. new 用来分配内存,主要用来分配值类型,比如 int,float32,struct 返回的是指针
  3. make 用来分配内存,主要用来分配引用类型 比如channel map slice

golang错误处理机制

1) 在默认情况下,当发生错误后(panic),程序就会推出(崩溃)
2)当发生错误后,可以捕获到错误,并进行处理,保证程序可以继续执行,还可以在捕获到错误后,给管理员一个提示 (邮件,短信)
3)
错误处理机制

  1. 1)go语言追求简洁优雅,所以go语言不支持传统的try…catch …finally 这种处理
  2. 2)go中引入的处理方式为defer panic recover
    1. go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。

错误处理的好处
进行错误处理后,程序不容易挂掉,如果加入预警代码,就可以让程序更加健壮。

自定义错误
go程序中支持自定义错误,使用errors.New和panic内置函数
1) error.New(“错误说明”) 会返回一个error类型的值,表示一个错误
2)panic 内置函数,接受一个interface{}类型的值(也就是任何值了)作为参数,可以接受error类型的变量,输出错误信息,并退出程序。、

数组和切片

数组可以存放多个同一类型数据,数组也是一种数据类型,在Go中数组是值类型。

go语言的数组地址是连续的
数组的各个元素的地址间隔是依据数组的类型决定

访问数组的元素
数组名[下标]
四种初始化数组的方式

  • var newsArray01 [3]int = [3]int {1,2,3}
  • var numsArray02 = [3]int{2,3,3}
  • var numsArray03 = […]int{6,7,8}
  • var names = [3]string{1:“tom”,0:“jack”,3:“marry”}

数组的遍历
方一:常规遍历
方二:for-range 结构遍历
for index,value := range array01{

}

  1. 1) 第一个返回值index是数组的下标
  2. 2)第二个value是在该下标位置的值
  3. 3)他们都是仅在for循环内部可见的局部变量
  4. 4)遍历数组元素的时候,如果不想使用下标index,可以直接把index标为下划线_
  5. 5)index 和value的名称不是固定的,即程序员可以自行制定,一般命名为index和value

数组使用注意事项和细节

  1. 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
  2. var arr []int 这时arr 就是一个slice切片
  3. 数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用
  4. 数组创建后,如果没有赋值,有默认值
    数组类型数组,默认值为0
    字符串数组, 默认值为""
    bool数组,默认值为false
  5. 使用数组的步骤,1.声明数组并开辟空间 2.给数组各个元素赋值 3 使用数组
  6. 数组的下标是从0开始的。
  7. 数组下标必须在指定范围内使用,否则报panic,数组越界
    比如 var arr [5]int 则有效下标为0-40
  8. go数组属值类型,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响。
  9. 如想在其他函数中,去修改原来的数组,可以使用引用传递(指针方式)
    10.长度是数组类型的一部分,在传递函数参数时需要考虑数组的长度。

切片 :动态的数组,保存不确定的数组
切片的基本介绍

  1. 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制
  2. 切片的使用和数组类似,遍历切片,访问切片的元素和求切片长度len(slice)都一样
  3. 切片的长度是可以变化的,切片是一个可以动态变化的数组
  4. 切片定义的语法:
    var 切片名 []类型

切片的容量是可以动态变化的
切片容量一般是长度的2倍

切片在内存中的形式–在内存中如何布局

  • 切片的地址 长度 容量
    从底层来说就是一个数据结构,struct 结构体

切片使用
方一:直接使用一个数组,然后用切片
方二:通过make来切片
基本语法:var 切片名 []type = make([],len,[cap])

  • 通过make方式创建切片可以指定切片的大小和容量
  • 如果没有给切片的各个元素赋值,那么就会使用默认值(int ,float=>0,string=>’’ bool=>false)
  • 通过make方式创建的切片对应的数组是有make底层维护,对外不可见,即只能通过slice去访问各个元素。
    方三:定义一个切片,直接就指定具体数组,使用原理类似make的方式。

方一和方二的区别
方一:直接引用数组,这个数组是先存在的,程序员可见
方二:通过make来创建切片,make也会创建一个数组,是有切片在底层进行维护程序员不可见。

切片遍历

  1. for循环常规方式遍历
  2. for-range结构遍历切片

切片注意事项和细节说明
切片初始化时 var slice = arr[startIndex:endIndex
说明: 从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
切片初始化,仍然不能越界,范围在[0-len(arr)]之间,但是可以动态增长

  1. 1)var slice = arr[0:end] 可以简写 var slice = arr[:end]
    1. var slice = arr[start:len(arr)] 可以简写var slice = arr[start:]
  2. 3)var slice = arr[0:len(arr)] 可以简写var slice =arr[:]
    cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素
    切片定义完成后,还不能使用,因为本省是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用
    切片可以继续切片
    用append函数,可以对切片进行动态追加
    切片的拷贝操作,切片使用copy内置函数完成拷贝。

string 和slice

  1. string底层是一个byte数组,因此string也可以进行切片处理。
  2. string 和切片在内存的形式
  3. string是不可变的,也就是说不能通过str[0] = ‘z’ 方式来修改字符串
  4. 如果需要修改字符串,可以先将string->[]byte/或者[]rune->修改->重写转成string

排序和查找

  • 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。
    (包括交换式排序法,选择式排序法和插入式排序法)
  • 外部排序法 数据量过大,无法全部加载到内存中,需要借助外部存储进行排序,
    (合并排序法和直接合并排序法)
    交换式排序法:
  1. 冒泡排序法
  2. 快速排序法

MAP

map是key-value数据结构,又称为字段或者关联数组,类似其他编程语言的的集合

var map变量名 map[keytype]valuetype
key 可以是什么类型
go中map的key可以是很多类型,比如bool,数字,string,指针,chanel ,还可以包含前面几个类型的接口,结构体,数组,
通常为int string

注意 slice,map还有function不可以作为key,因为这几个没法用==来判断

valuetype的类型和key基本一行,
通常是数字(整数,浮点数)string struct

生命是不会分配内存的,初始化需要make,分配内存后才能赋值和使用

map总结的几点

  1. map在使用前一定要make
  2. map的key是不能重复的,如果重复了,则以最后这个key-value为准
  3. map的value是可以相同的
  4. map的key-value是无序的。

map 使用细节

  1. map是引用类型,遵守引用类型传递的机制,再一个函数接受map,修改后,会直接修改原来的map
  2. map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长键值对(key-value)
  3. map的value也经常使用struct类型,更适合管理复杂的数据

go面向对象编程说明

  1. 1)go支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言,所以我们说golang支持面向对象编程特性是比较准确的。
    1. go中没有类class,go语言的结构体和其他编程语言的类有同等地位,go是基于struct来实现oop特性的。
  2. 3)go面向对象编程非常简洁,去掉了传统OOP语言的继承,方法重载,构造函数和析构函数,隐藏的this指针等
  3. 4)go仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继承,go中没有extend关键字,继承是通过匿名字段来实现的。
  4. 5)go面向对象很优雅,oop本身就是语言类型系统(type system)的一部分,通过接口关联,耦合性低,非常灵活,go中面向接口编程

结构体注意细节
1.结构体的所有字段在内存中是连续的
指针本身的地址还是连续的,但是指针指向的地址不一定时连续的。
2.结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字,个数和类型)
3.结构体进行type重新定义(相当于取别名)golang认为是新的数据类型,但是相互间可以强转
4.struct的每个字段上,可以写一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化

struct方法
go中的方法是作用在指定的数据类型上的(和指定的数据类型绑定)。因此自定义类型,都可以有方法,而不仅仅是struct.


方法的声明
func (recevier type)methodName (参数列表)(返回值列表){
方法体
return 返回值
}

  1. 参数列表 表示方法输入
  2. recevier type 表示这个方法和type这个类型进行绑定,或者说该方法作用域type类型
  3. recevier type type可以是结构体,也可以其他的自定义类型
  4. receiver:就是type类型的一个变量(实例),比如Person结构体的一个变量(实例)
  5. 参数列表:表示方法输入
  6. 返回列表:表示返回的值,可有多个
  7. 方法主体:表示为了实现某一功能代码块
  8. return 语句不是必须的。

方法的注意事项和细节讨论 重要

  1. 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方法
  2. 如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理。
  3. go中的方法作用在指定的数据类型上,即(和指定的数据类型绑定)。因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32 等都可以有方法。
  4. 方法的访问范围控制规则,和函数一样,方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问
  5. 如果一个变量实现了string()这个方法,那么fmt.Println()默认会调用这个变量的string()进行输出

方法和函数区别

  1. 调用方式不一样
    函数的调用方式 : 函数名(实参列表)
    方法的调用方式:变量名.方法名(实参列表)

  2. 对于普通函数,接受者为值类型时,不能讲指针类型的数据直接传递,反之亦然。

  3. 对于方法(比如struct方法)接受者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。

总结:

  1. 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和那个类型绑定。
  2. 如果是和值类型,比如(P,Person)则是值拷贝,如果和指针类型,比如是(p *Person)则是地址拷贝。

面向对象编程应用实例
步骤

  1. 声明(定义)结构体,确定结构体名。
  2. 编写结构体的字段
  3. 编写结构体的方法

面向对象编程-抽象
面向对象三大特性:封装 继承 多态
go中没有特别强调封装,
继承可以解决代码复用,当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法。
其他的结构体不需要重新定义这些属性和方法,只需要嵌套一个Student匿名结构体即可。
也就是说,在go中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。

嵌入一个匿名结构体实现继承,
继承的深入讨论、

  1. 1)结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段,方法,都可以使用
  2. 2)匿名结构体字段访问可以简化
  3. 3)当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分。
  4. 4)结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有相同的字段和方法)在访问时,就必须明确指定匿名结构体名字,否则编译器报错。
  5. 5)如果一个struct嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段和方法时,必须带上结构体的名字。
  6. 6)嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值。

多重继承

  • 如一个struct嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。
  • 为了保证代码的间接性,建议不要使用多重继承

接口 interface 减少耦合 松耦合 高类聚

go中 多态特性主要是通过接口来体现的
基本介绍

  • interfaceleixi8ng可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量,到某个自定义类型(比如结构体Phone)要使用的时候,再根据具体情况把这些方法写出来。
    基本语法
    type 接口名 interface{
    method1 (参数列表)返回值列表
    method2 (参数列表) 返回值列表
    }
    func (t 自定义类型) method(参数列表) 返回值列表{
    //方法实现
    }
    说明
  1. 接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法,接口体现了程序设计的多态和高内聚低耦合的思想。
  2. go中的接口,不需要显示的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口,go中没有implement这样的关键字。

接口的注意事项和细节

  1. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义的变量(实例)
  2. 接口中的所有方法都没有方法体,即都是没有实现的方法
  3. 在go中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口
  4. 一个自定义类型只能实现了某个接口,才能将该自定义类型的实例(变量)赋给接口的类型
  5. 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型
  6. 一个自定义类型可以实现多个接口
  7. go接口中不能有任何变量
  8. 一个接口(比如A接口)可以继承多个别的接口(比如 B接口,C接口)这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
  9. interface类型默认是一个指针(引用类型)如果没有对interface初始化就使用,那么会输出nil
  10. 空接口interface{}没有任何方法,所以所有类型都实现了空接口

go基于函数(方法)实现。

接口和继承的关系

  1. 当A结构体继承了B结构体,那么A结构就自动的继承了B结构体的字段和方法,并且可以直接使用
  2. 当A结构体需要扩展功能,同时不希望去破坏继承关系。

实现接口可以看做是对继承的一种补充

1.接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法
2. 接口比继承更加灵活
接口比继承更加灵活,继承是满足is-a的关系,而接口只需要满足like-a的关系。
3. 接口在一定程度上实现代码解耦

面向对象的多态
变量(实例)具有多种形态,
go语言中,多态是通过接口实现的。可以按照统一的接口来调用不同的实现,这时接口变量就呈现不同的形态。

golang 在创建结构体实例(变量)时,可以直接指定字段的值。
创建结构体变量时指定字段值方式

  1. 方一:
    var stu1 Student = Student{“tome”,10}
    stu2 := Student{“tom”,10}
  2. 方二
    var stu *Student = &Student{“smith”,20}
    var stu2 *Student = &Student{}

go 工厂模式
golang的结构没有构造函数,,通常可以使用工厂模式来解决这个问题。

使用工厂模式实现跨包创建结构体实例(变量)的案例
如果model包的结构体变量首字母大写,引入后,直接使用,没有问题。
如果model包的结构体变量首字母小写,引入后,不能直接使用,可以工厂模式解决。

文件的基本介绍
文件是数据源(保存数据的地方)
文件在程序中是以流的形式来操作的,
打开文件的方法 Open 关闭文件的路径Close
os 包 Variable
os.Args是一个string的切片,用来存储所有的命令行参数。
go中的json
json (javascript object notation )是一种轻量级的数据交换格式,易于人阅读和编写,同事也易于机器解析和生成。

类型断言,由于接口是一般类型,不知道具体类型,
如果要转成具体类型,就需要使用类型断言。

posted @ 2019-07-19 12:44  liulonglong  阅读(103)  评论(0编辑  收藏  举报