Go总结(2)

struct
go中struct结构默认字段都会有零值,故不能用nil来判断struct是否为空,可通过额外的字段来判断struct是否填充或为空

type Demo struct{
ready bool

name string
//其他字段
}
在初始化的时候必须将ready设置为true
var d Demo
if !d.ready{
//do stuff
}

Web工作方式

Go通过ListenAndServer来建立web服务器,底层是初始化一个server对象,然后调用net.Listen(“tcp”,addr)来监听端口。
调用srv.server(net.Listener)函数来处理接收客户端请求。函数里面为一个for{},首先通过accept接受请求,接着创建一个Conn,最后单独开一个goroutine取执行:go c.server()。
用户的每一次请求都是一个新的goroutine去执行。
conn通过解析requestc.readRequest()获取相应的handler := c.server.Handler,它本质是一个路由器,通过它来匹配url跳到对应的handle函数。
可通过`http.HandleFunc(“/”,sayhelloName)来注册请求的路由规则。

OS获取环境变量
os.getenv()获取环境变量获取不到最新设置的环境变量,最新设置的需要重新启动电脑获取
基本类型
这两天在搞反射,看到Go的基础数据类型那么多,int,int32,int64都有,而且运算过程中还需要转换,所以抽空看了些博客以及官方文档。

int跟uint

有符号:int8,int16,int32,int64
无符号:unit8,unit16,unit32,uint64
int和unit取决于操作系统,在32位系统就是32字节,在64位系统就是64字节
int跟int32不是相同的类型,虽然在特定的场景下它们大小相同,但是在运算过程中需要转换
byte是unit8的别名,rune是int32的别名

浮点类型为float32和float64
浮点类型在运算过程中可能存在精度丢失的情况

string

字符串是不可变的,一旦创建,就不能改变字符串的内容
可以使用内置函数len来发现s的长度,如果字符串为常量,则length是编译时常量。
字符串的字节可以通过索引来获取,但是取元素的地址是非法的,即&s[i]是无效的。

反射
反射在计算机中是程序检查自己结构的一种能力,尤其是通过类型,它是元数据编程的一种方式,也是混乱的重要来源每个语言的反射模型都不同(很多语言根本不支持它)

Type And interface
因为反射是建立在类型系统上,让我们先回顾一下Go中的类型。
Go是静态类型语言,每个变量都有一个静态类型,即在编译时就已知被固定上一种类型:int, float32, &MyType, []byte
type MyInt int

var i int
var j MyInt

变量i和j具有不同的静态类型,虽然他们具有相同的底层类型,但如果没有转换,则无法将他们分配给彼此。
interface可以存储任何具体的值,interface包括:

变量包括(type,value)两部分,这也是为什么nil != nil的原因
type包括static type和concrete type,static type是编辑时就看到的类型,而concrete type是runtime看到的类型

反射就是建立在类型之上的,Golang的指定类型的变量的类型是静态的(也就是指定int、string这些变量,它的type是static type),在创建变量的时候就已经确定,反射主要于Golang的interface有关(它的类型是concrete type),只有interface类型才有反射之说。
API
以下是一些API
reflect:
TypeOf(interface{}) Type : 返回接口中保存值的类型,i为nil值返回nil
ValueOf(interface{}) Value : 返回一个初始化为i接口保管的具体值的Value,但i为nil时返回Value零值
New(Type) Value:返回一个指向类型为Type的新申请的零值的指针。

Type:
Kind():返回该接口的具体类型
Name():返回类型名
Elem():返回该类型的元素类型,如果Kind不是Array,Chan,Map,Slice,Ptr会panic

Value:
Append(s Value,x …Value) Value: s需为切片类型的Value值,x需为s的元素类型的Value值,将x复制给s并且返回s
Type():返回v持有的类型的Type表示
Elem() Value:返回v持有的接口或者指针保管值的Value封装,如果v的Kind不是interface或者Ptr将会panic
Kind():同上一致
CanSet():判断v持有的值是否能更改,只有当Value持有值为Ptr并且为共有类型时,它才可以被修改。
Set(x Value):将v的持有值修改为x的持有值
SetInt(x Int64)
SetString(s string)
….

更多的可参考官方文档:https://go-zh.org/pkg/reflect/#Value.Convert
反射讲得比较好的一篇文章:https://juejin.im/post/5a75a4fb5188257a82110544
Go运行时
尽管Go编译器产生的是本地可执行代码,这些代码仍旧运行在Go的runtime(这部分的代码可以在runtime包中找到)当中,这个runtime类似虚拟机,它负责管理包括内存分配、垃圾回收、栈处理、goroutine、channel、slice、map和reflection等等。
Interface
Go中的interface并不是显示实现的,这就导致,一个方法接收的类型为IPerson,但是虽然我的Student对象已经实现了IPerson,但是还是不要在通过方法去new实现返回IPerson对象
type Student struct{
name string
age int
}

func newIPerson(name string,age int) IPerson{
return Student{
name : name,
age : age,
}
}

切片

make([]int,l,c) ,l为长度,c为容量,不传c则容量等于长度
底层还是数组,通过len()获取长度,cap()获取容量

append之后返回的是一个新的切片

扩容:

capacity小于1000时,两倍扩容

capacity大于1000时,增长因子为1.25,25%扩容

赋值:将一个切片赋值给另一个切片可指定索引

第一个索引:指定切片的头部
第二个索引:指定切片长度的尾部
第三个索引:限制切片的容量

参考下面代码:
a := []int{1, 2, 3, 4, 5}
b := a[1:]
c := a[:4]
d := a[1:4]
e := a[2:3:4]
fmt.Println(“a”, len(a), cap(a))
fmt.Println(“b”, len(b), cap(b))
fmt.Println(“c”, len(c), cap(c))
fmt.Println(“d”, len(d), cap(d))
fmt.Println(“e”, len(e), cap(e))

//打印结果
a 5 5
b 4 4
c 4 5
d 3 4
e 1 2

for-range返回的是每个元素的副本,而不是引用
切片在函数件传递还是以值传递的方式传递,由于切片的尺寸很小,在函数间复制和传递切片的成本也很低。在64位结构的机器上,一个切片需要24个字节,指针字段8字节,长度和容量分别需要8字节,由于与切片关联的数据包含在底层数组里面,不属于切片本身,所以将切片复制给人以数组时对底层数组大小都不会有影响。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理