Browsed by
月份:2016年11月

Effective Go & GoFAQ 阅读笔记

Effective Go & GoFAQ 阅读笔记

Effective go: https://golang.org/doc/effective_go.html

Go FAQ: https://golang.org/doc/faq

下面是对以上两篇文章内相关内容的记录与解释/总结

Interface

某一个 type “implement” 这个 interface 的话,只要实现这个interface的全部方法即可 不过这里有一些容易产生误区的地方,看下面这个例子

 

Equaler是一个interface, 下面看这两个例子

type T并没有实现Equaler interface 因为参数类型不是 Equaler 而是一个具体的类型 T

这个问题很容易理解, 试想一下其他某一个type implement了Equaler类型(假设为Q) 而 t.Equal(Q) 是不合法的 因为Q不是T类型, 所以 T 并没有实现Equaler这个interface 因为Equaler接口要求只要满足type为Equaler就都可以作为参数传递给Equal

下面这个才是T implement Equaler的例子

 

interface 的 value = nil 不代表interface为nil, interface的结构为type, value两部分 下面这个代码永远会返回错误

上述代码中 Process成功将返回一个p(type=*DemoError, value=nil)这个与nil进行对比的时候,永远会返回假 因而不要使用这种方式返回error相对的,直接return Error即可(待斟酌)

 

map slice channel存的是引用, array 存的是value

在go中函数传递的都为按值传递, 如果传递一个array并且对array进行修改,修改是无法保留下来的,这个和C语言中传递array不一样,C语言传递数组传递的是数组的地址,如果想要修改数组中的元素, 可以传递slice,并不是说slice的传递是按照地址传递,slice传递依旧是按值传递,不过slice包含三部分 len, cap, reference to array  而对slice操作的时候,操作的就是它下面指向的array,因而可以修改元素,不过没有办法append元素或者remove元素,这些操作会修改len 和 cap,在函数返回的时候len和cap的修改会丢失

Idiom

Almost Never, Do not use a pointer to an interface

Do not communicating by sharing memory, Share memory by communicating

Concurrency is not Parallelism

 

Naming

对于Getter的名字,不要使用GetXXX

interface type name end with -er

 

Control Flow

if often exit current function

e.g:

if 经常直接用于退出这个函数,执行块等,这样就可以省去多余的else

 

switch可以用来判断value的类型

用法为

 

break 可以跳出多层循环

用法为 break Label

注意Label一定要打在某一个循环的for statement之前,位置错误的话会报编译错误

 

Function

 

使用named return value

使用这种形式

而不是这种

 

使用 defer 做cleanup

当打开文件, 数据库链接,或者TCP链接的时候,我们需要在使用完毕之后关闭链接, 在传统的C语言中, 在函数退出的地方编写cleanup相关的代码 而在go里, 有一个书写,阅读都更友好的方式,即使用defer

 

这种写法的好处有两点(至少)

  1. 在打开的代码之后马上就书写关闭,便于排查代码中的问题,提高了代码的可读性
  2. 如果函数内有多个返回点,不需要多次书写cleanup代码,只要一次即可

不过在使用的时候要注意一点: 一定要在确保成功操作之后(如上述代码,确保文件成功打开之后)再执行defer cleanup,不然程序在打开f失败的时候,调用Close就会产生panic

 

Data

make and new

make创建的是对应type的一个实例 new创建的是一个type实例的指针

new和make都会将对象初始化为0

 

println , printf %s/%v recursion hell

当使用println/printf (%v/%s)打印自己定义的结构的信息时 要注意避免无线递归

看下面的代码

 

这段代码会导致无限递归死循环

原理就是 printf %s, %v会调用相应type的String()函数, 而在String函数内我们又使用了%v,又会去调用String()函数,因而就无限递归了

这里只要做一个修改就能避免这个递归问题

 

将 f 类型转换为string 内置的类型会自动进行处理,不会再去调用Forever类型的String()函数

 

Append a slice to a slice

将一个slice append到另一个slice的语法是这样的

一定要有那三个”.”

 

Concurrency Tips

  • Only one goroutine can access the value at any time
  • Do not spawn unlimited go routines
  • using goroutines and channel can build non-blocking RPC system
  • [OFFTOPIC] Channel can use as queue, only in single goroutine(e.g leaky buffer)
APUE 3e 部分习题整理 Chap5

APUE 3e 部分习题整理 Chap5

Chapter5

5.1 使用setvbuf实现setbuf

根据 man手册 setbuf(FILE *stream, char *buf) 中如果指定 buf == NULL 那么就是关闭 buf,  如果指定 buf != NULL 那么就创建一个 BUFSIZ 大小的 buffer 供流使用 因而实现的代码如下

5.5 对标准I/O流如何使用fsync

fsync 需要的参数是 fd 描述符,因而只要能获得文件 FILE 结构体的 fd 值即可

这里一定要注意: 在使用fsync的时候一定要fflush流的缓冲区 fsync是将内核里的缓存数据写入磁盘/文件, 而对于打开的文件

是全缓冲的,也就是说没有写满IO缓冲区之前是不会去写入内核缓冲区的 因而就算调用fsync也没有什么用呢~ 你需要先把数据从 IO buffer中写入内核buffer然后fsync才有用 所以一定要fflush

 

P.S.:天真的窝以为这题只是考察能不能把FILE结构体给找到,并拿出来相应的fileno,没想到我太天真了=o=

FILE 结构体中的 _fileno就是相应的文件描述符

5.6 题略 (Page 141[175英文版])

虽然看glibc的源码暂时没有看懂,不过查到的资料包括http://c-faq.com/stdio/stdinflush2.html文档都说明了这个事实就是 scanf, getchar, gets, fgets在调用的时候都会flush buffer

5.7 用FreeBSD上的funopen实现fmemopen

代码暂略

 

 

tmux 终端效率利器

tmux 终端效率利器

重度终端使用者的话如果没有一个好的终端多任务管理的工具是非常痛苦的, tmux是一个非常好用的终端多任务多session多窗口管理工具 功能十分强大 具体的介绍可以看这里

https://raw.githubusercontent.com/tmux/tmux/master/FAQ

效果图

cad50898-6128-49cf-a3d2-c92a08b95e24

 

2ec6c6ef-04af-4546-8a95-36671f19f207

 

tmux的manpage十分长,不是所有的功能都会常用到,这里有一个cheatsheet记录了常用的功能

https://tmuxcheatsheet.com/

tmux-powerline 非常美观实用的一个tmux工具

github repo  https://github.com/erikw/tmux-powerline

下面是各种个人配置的tip

修改tmux默认Ctrl b为其他键位

修改tmux窗口的名字 并保持名字不会更改

然后source配置文件让设置生效

在tmux中开启新的窗口的时候,默认以最初启动tmux的时候的路径开启,这样很不方便,配置~/.tmux.conf让其以当前目录创建新的窗口和分割,增加如下三行配置

向所有当前window的pane(窗口)内输入同样的指令