go 入门学习

Go语言入门,初学要点摘要记录。

if语句:

“如果你必须使用这种形式,则把尽可能先满足的条件放在前面。”

if condition{

}else {

}

“Go 代码的常见写法是省略 else 部分”

if inistialization; condition{

}

error: var err error

ret, _ = myfunction()

一个典型的用法: “if err := file.Chmod(0664); err !=nil { fmt.Println(err) return err }”

Switch语句:

“Go 语言中的 switch 结构使用上更加灵活。它接受任意形式的表达式:”

switch: fallthrough , default,

“。switch 语句的第二种形式是不提供任何被判断的值(实际上默认为判断是否为 true)”

“witch 语句的第三种形式是包含一个初始化语句:

switch initialization {

}

字符编码问题:

“,ASCII 编码的字符占用 1 个字节,既每个索引都指向不同的字符,而非 ASCII 编码的字符(占有 2 到 4 个字节)不能单纯地使用索引来判断是否为同一个字符”

“for ix, val := range coll { }。

要注意的是,val 始终为集合中对应索引的值拷贝,因此它一般只具有只读性质,对它所做的任何修改都不会影响到集合中原有的值(”

Go中不支持函数重载 , 但是支持 函数调用 其他返回类型一致的函数作为入参

defer语句,用来标示语句在return之前才执行, 用来释放资源 和进行代码的追踪。

函数是可以作为其他函数的参数来进行传递的--回调

匿名函数:

“fplus := func(x, y int) int { return x + y },然后通过变量名对函数进行调用:fplus(3,4)。”

“关键字 defer经常配合匿名函数使用,它可以用于改变函数的命名返回值。”

闭包很像c语言中的define, 也常用在debug中

数组: 可以进行切片,slice更像是list. 带标签的结构体: -- 像是对结构体中变量的相关描述,这些描述信息一般情况下是不可见的,可以用 reflect field来进行检测

结构体

可以有 匿名字段 “匿名字段本身可以是一个结构体类型,即 结构体可以包含内嵌结构体。”

内嵌or组合--可以用继承的概念进行类比

“在一个结构体中对于每一种数据类型只能有一个匿名字段。” “两个字段拥有相同的名字(可能是继承来的名字)时该怎么办呢?” --重载,外层覆盖内层

“在 Go 语言中,结构体就像是类的一种简化形式” 方法:感觉略奇葩,在一个包内,可以被同类型函数调用, 1. 怎么保证竞争 2.如何私有?

“receiver_type 叫做 (接收者)基本类型,这个类型必须在和方法同样的包中被声明。” 用指针调用方法,可以减少调用的代价。

“指针方法和值方法都可以在指针或非指针上被调用,”

未导出字段: “提供 getter 和 setter 方法。对于 setter 方法使用 Set 前缀,对于 getter 方法只适用成员名。”

“结构体内嵌和自己在同一个包中的结构体时,可以彼此访问对方所有的字段和方法。” ** 规范** “想写规范的 Go 程序,就应该遵守这些约定,给方法合适的名字和签名,就像那些通用方法那样。这样做会使 Go 开发的软件更加具有一致性和可读性。比如:如果需要一个 convert-to-string 方法,应该命名为 String(),而不是 ToString()”

“在 Go 中,类型就是类(数据和关联的方法)。Go 不知道类似面向对象语言的类继承的概念。继承有两个好处:代码复用和多态。”

“在 Go 中,代码复用通过组合和委托实现,多态通过接口的使用来实现:有时这也叫 组件编程(Component Programming)。”

“格式化描述符 %T 会给出类型的完全规格,%#v 会给出实例的完整输出,包括它的字段(在程序自动生成 Go 代码时也很有用)。”

要注意无限迭代调用问题。

垃圾回收: “Go 开发者不需要写代码来释放程序中不再使用的变量和结构占用的内存,在 Go 运行时中有一个独立的进程,即垃圾收集器(GC)”

一个对象从内存移除之前执行特殊操作: “runtime.SetFinalizer(obj, func(obj *typeObj))”

接口: “接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。”

“类型不需要显式声明它实现了某个接口:接口被隐式地实现。多个类型可以实现同一个接口。

实现某个接口的类型(除了实现接口方法外)可以有其他的方法。

一个类型可以实现多个接口。

接口类型可以包含一个实例的引用, 该实例的类型实现了此接口(接口是动态类型)。”

类型检测: “可以用 type-switch 进行运行时类型分析,但是在 type-switch 不允许有 fallthrough 。”

“解析诸如 JSON 或 XML 编码的数据,类型测试和转换会非常有用。”

“测试一个值是否实现了某个接口”

“panic(“fail”) 用于停止处于在非正常情况下的程序”

“io 包里的 Readers 和 Writers 都是不带缓冲的,bufio 包里提供了对应的带缓冲的操作,在读写 UTF-8 编码的文本文件时它们尤其有用。”

“在实际编程中尽可能的使用这些接口,会使程序变得更通用,”

“反射是用程序检查其所拥有的结构,尤其是类型的一种能力;这是元编程的一种形式。反射可以在运行时检查类型和变量,例如它的大小、方法和 动态 的调用这些方法”

v.canSet()?

“要想让其可设置我们需要使用 Elem() 函数,这间接的使用指针:v = v.Elem()”

可以反射变量,反射接口,反射结构体。

面向对象 传统面向对象: 数据和方法,封装在一起。

“Go 没有类:数据(结构体或更一般的类型)和方法是一种松耦合的正交关系。”

“像 Python,Ruby 这类语言,动态类型是延迟绑定的(在运行时进行):方法只是用参数和变量简单地调用,然后在运行时才解析(它们很可能有像 responds_to 这样的方法来检查对象是否可以响应某个方法,但是这也意味着更大的编码量和更多的测试工作)”

“Go 的实现与此相反,通常需要编译器静态检查的支持:当变量被赋值给一个接口类型的变量时,编译器会检查其是否实现了该接口的所有函数”

Go中的面向对象: 没有类,松耦合。 封装,继承,多台。

Go中的协程:

多线程范式: tpc: “thread-per-connection 模型不够有效。 加锁,保证只有一个线程能够访问相关的资源。 csp: Communicating Sequential Processes(顺序通信处理) mpm: “message passing-model(消息传递模式)”,用在erlang

“在 Go 中,应用程序并发处理的部分被称作 goroutines(协程),它可以进行更有效的并发运算。”

“协程是通过使用关键字 go 调用(执行)一个函数或者方法来实现的(也可以是匿名或者 lambda 函数)”

虽然 Go语言中仍有指针的存在,但并不允许进行指针运算。

尽管 Go 语言像其它静态语言一样执行本地代码,但它依旧运行在某种意义上的虚拟机,以此来实现高效快速的垃圾回收(使用了一个简单的标记-清除算法)

因为 Go 语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口(interface)的概念来实现多态性

作为强类型语言,隐式的类型转换是不被允许的,记住一条原则:让所有的东西都是显式的。

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。

Go 语言一个非常好的目标就是实现所谓的复杂事件处理 https://en.wikipedia.org/wiki/Complex_event_processing

因为垃圾回收和自动内存分配的原因,Go 语言不适合用来开发对实时性要求很高的软件。

为了简化设计,不支持函数重载和操作符重载 为了避免在 C/C++ 开发中的一些 Bug 和混乱,不支持隐式转换 Go 语言通过另一种途径实现面向对象设计(第 10-11 章)来放弃类和类型的继承 尽管在接口的使用方面(第 11 章)可以实现类似变体类型的功能,但本身不支持变体类型 不支持动态加载代码 不支持动态链接库 不支持泛型 通过 recover 和 panic 来替代异常机制(第 13.2-3 节) 不支持断言 不支持静态变量

如果想知道结构体类型T的一个实例占用了多少内存,可以使用:size := unsafe.Sizeof(T{})。

Chen Xi
Chen Xi
Software Engineer

Related