command line - How to change visudo editor from nano to vim? - Ask Ubuntu

1
sudo update-alternatives --config editor

Ubuntu修改locale问题解决-Cannot set language to “zh_CN.utf-8”

1
sudo dpkg-reconfigure locales
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
" Vim-Plug {{{
call plug#begin('~/.vim/plugged')
Plug 'junegunn/vim-easy-align'
Plug 'valloric/youcompleteme'
Plug 'altercation/vim-colors-solarized'
Plug 'https://github.com/junegunn/vim-github-dashboard.git'
Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'
Plug 'scrooloose/nerdtree', {'on': 'NERDTreeToggle'}
Plug 'tpope/vim-fireplace', {'for': 'clojure'}
Plug 'rdnetto/YCM-Generator', {'branch': 'stable'}
Plug 'fatih/vim-go', {'tag': '*'}
Plug 'nsf/gocode', {'tag': 'v.20150303', 'rtp':'vim'}
call plug#end()
" }}}

" General {{{
set nocompatible
set nobackup
set noswapfile
set history=1024
set autochdir
set whichwrap=b,s,<,>,[,]
set nobomb
set backspace=indent,eol,start whichwrap+=<,>,[,]
set clipboard+=unnamed " Vim的默认寄存器和系统剪贴板共享
set winaltkeys=no
" }}}

" GUI {{{
"colorscheme tomorrow-night
set cursorline
set hlsearch
set incsearch
set number
set splitbelow
set splitright
"set guifont=Inconsolata:h20
" }}}

" Format {{{
set autoindent
set smartindent
set tabstop=4
set expandtab
set softtabstop=4
"set foldmethod=indent
set shiftwidth=4
set ls=2
syntax on
" }}}

" Keymap {{{
let mapleader=","

" 标签操作
map <leader>tn :tabnew<cr>
map <leader>tc :tabclose<cr>
map <leader>th :tabp<cr>
map <leader>tl :tabn<cr>

" 移动分割窗口
nmap <C-j> <C-w>j
nmap <C-k> <C-w>k
nmap <C-h> <C-w>h
nmap <C-l> <C-w>l

" }}}
set completeopt-=preview

初始值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Na struct {
name string
}

type Ia interface {
}

func main() {
var e error
var na Na
var ia Ia
fmt.Println(na, e, ia)

n := new(Na)
i := new(Ia)
fmt.Println(n, i)

c := make([]byte, 2, 5)
fmt.Println(c)
}
/* output:
{} <nil> <nil>
&{} 0xc042008270
[0 0]
*/

make 和 new

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var v = make([]byte, 10, 20)
v[0] = 0
v[1] = 1
v[2] = 2
v[9] = 32
v = v[:cap(v)] // We can grow s to its capacity by slicing it again https://blog.golang.org/go-slices-usage-and-internals
v[10] = 33
fmt.Println(v)

var n = new([]byte)
n = &v
fmt.Println(*n)
/* output:
[0 1 2 0 0 0 0 0 0 32 33 0 0 0 0]
[0 1 2 0 0 0 0 0 0 32 33 0 0 0 0]
*/

How to check if a map contains a key in go?

1
2
3
if val, ok := dict["foo"]; ok {
//do something here
}

Removing item(s) from a slice, while iterating in Go

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func main() {
arr := []int64{1, 2, 3, 4, 6, 8, 9, 10, 11, 23}
for i := len(arr) - 1; i >= 0; i-- {
if arr[i]%2 == 0 {
arr = append(arr[:i], arr[i+1:]...)
}
}
fmt.Println(arr)
}

过滤selected为false的商品规格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 方案1 
specProps := product.SpecProps
spec := models.Spec{}
err := json.Unmarshal([]byte(specProps), &spec)
if err == nil {
sItem := make([]models.SpecChildren, 0)
for _, v := range spec.Spec {
scItem := make([]models.SpecChildrenItem, 0)
for _, vv := range v.Children {
if vv.Selected {
vv.Selected = false
scItem = append(scItem, vv)
}
}
v.Children = scItem
sItem = append(sItem, v)
}
spec.Spec = sItem

data, err := json.Marshal(spec)
if err == nil {
product.SpecProps = string(data)
}
}

// 方案2
specProps := product.SpecProps
spec := models.Spec{}
err := json.Unmarshal([]byte(specProps), &spec)
if err == nil {
for j := 0; j < len(spec.Spec); j++ {
v := &spec.Spec[j] // Note: need pointer
for i := len(v.Children) - 1; i >= 0; i-- {
if !v.Children[i].Selected {
// https://vbauerster.github.io/2017/04/removing-items-from-a-slice-while-iterating-in-go/
v.Children = append(v.Children[:i], v.Children[i+1:]...)
}
}
}

specData, err := json.Marshal(spec)
if err == nil {
product.SpecProps = string(specData)
}
}

Converting Go struct to JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"encoding/json"
)

type User struct {
name string
}

func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}

Go json.Unmarshal array

  • Decode top level JSON array into a slice of structs in golang
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package main

    import "fmt"
    import "encoding/json"

    type PublicKey struct {
    Id int
    Key string
    }

    type KeysResponse struct {
    Collection []PublicKey
    }

    func main() {
    keysBody := []byte(`[{"id": 1,"key": "-"},{"id": 2,"key": "-"},{"id": 3,"key": "-"}]`)
    keys := make([]PublicKey,0)
    json.Unmarshal(keysBody, &keys)
    fmt.Printf("%#v", keys)
    }

GET & POST 请求和转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
var cfg = beego.AppConfig

type AddressController struct {
baseController
}

func (ac AddressController) Address() {
userId := ac.GetString("user_id")
var url = cfg.String("third::user_url") + "/user/address?user_id=" + userId
body, err := get(url)
if err != nil {
logs.Error("get Address error:", err)
return
}
ac.Data["json"] = string(body)
ac.ServeJSON()
}

func (ac AddressController) AddAddress() {
userId := ac.GetString("user_id")
var url = cfg.String("third::user_url") + "/user/add_address?user_id=" + userId

body, err := post(url, ac.Ctx.Input.RequestBody)
if err != nil {
logs.Error("post AddAddress error:", err)
return
}
ac.Data["json"] = string(body)
ac.ServeJSON()
}

func get(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}

func post(url string, data []byte) ([]byte, error) {
body := bytes.NewBuffer(data)
resp, err := http.Post(url, "application/json;charset=utf-8", body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}

参考资料

Go语言里面提供了一个完善的net/http包,通过http包可以很方便的就搭建起来一个可以运行的Web服务。
同时使用这个包能很简单地对Web的路由,静态文件,模版,cookie等数据进行设置和操作。

万变不离其宗,Go的Web服务工作也离不开我们第一小节介绍的Web工作方式。

Go为了实现高并发和高性能, 使用了goroutines来处理Conn的读写事件, 这样每个请求都能保持独立,相互不会阻塞,可以高效的响应网络事件。这是Go高效的保证。
https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/03.4.md

分页

1
2
3
4
5
6
o := orm.NewOrm()
qs = o.QueryTable("user");
var pageSize = 50 // 一页50条
var pageNo = 3 // 准备取第三页
// qs.Limit("[取多少个]","[偏移行数]");
qs = qs.Limit(pageSize, pageNo*pageSize) // 请注意和MySQL语法的区别:LIMIT 50*3, 50

解析[]orm.Params

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func analyseParams(params *[]orm.Params) {
keyImage := "image"
keyStatus := "status"
keyEndAt := "end_at"
for _, param := range *params {
// replace image
if vv, ok := param[keyImage]; ok {
r := reflect.ValueOf(vv)
if r.Kind() == reflect.String {
temp_arr := strings.Split(r.String(), ",")
param[keyImage] = commons.ImagePath(temp_arr[0])
}
}

// add status
if vv, ok := param[keyEndAt]; ok {
r := reflect.ValueOf(vv)
if r.Kind() == reflect.String {
now := time.Now().UnixNano()
startTime, err := time.Parse("2006-01-02 15:04:05", r.String())
if err != nil {
logs.Error("转换时间错误:", err)
continue
}
if startTime.UnixNano() > now {
param[keyStatus] = "notbegin"
}
}
}

// delete marketable_at
delete(params, "marketable_at")
}
}

排序

1
2
3
4
5
6
// 顺序
sort.Ints(a []int);
sort.Strings(a []string);
// 逆序 https://stackoverflow.com/questions/18343208/how-do-i-reverse-sort-a-slice-of-integer-go
sort.Sort(sort.Reverse(sort.IntSlice(keys)))
sort.Sort(sort.Reverse(sort.StringSlice(keys)))

The Command

标准命令详解

go - How to get all dependency files for a program using Golang - Stack Overflow

1
go get -d -v ./...

... is a special pattern, tells to go down recursively

格式化整个目录

1
gofmt -w -l src

fmt占位符

strconv数字转换

  • strconv.Itoa (数字转换为字符串)
  • strconv.Atoi (字符串转换为数字)

time

1
2
timeStr := time.Now().Format("2006-01-02 15:04:05")
timeStr = time.Parse("2006-01-02 15:04:05", time.Now)

json

特点:

简洁 快速 安全
并行 有趣 开源
内存管理,数组安全,编译迅速

可执行文件

Executable commands must always use package mainhttps://golang.org/doc/code.html#PackageNames
package main 包表示它是一个可独立运行的包,它在编译后会产生可执行文件。
https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.1.md#详解
除了main包之外,其它的包最后都会生成*.a文件(也就是包文件)并放置在$GOPATH/pkg/$GOOS_$GOARCH中

每一个可独立运行的Go程序,必定包含一个package main,在这个main包中必定包含一个入口函数main,而这个函数既没有参数,也没有返回值。

Go使用package(和Python的模块类似)来组织代码。main.main()函数(这个函数位于主包)是每一个独立的可运行程序的入口点。Go使用UTF-8字符串和标识符(因为UTF-8的发明者也就是Go的发明者之一),所以它天生支持多语言。

import

  • 点操作
  • 别名操作
  • _操作

变量和常量

常量使用关键字const表示,不可用:=语法定义。
var 语句定义了一个变量列表;
进一步阅读: https://blog.golang.org/gos-declaration-syntax

:=这个符号直接取代了var和type,这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;
在函数外部使用则会无法编译通过,所以一般用var方式来定义全局变量。
_(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。

零值:

数值:0
布尔:false
指针:nil

指针:

& 符号会生成一个指向其作用对象的指针;
* 符号表示指针指向的底层的值;

那么到底传指针有什么好处呢?

传指针使得多个函数能操作同一个对象。
传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。
Go语言中channel,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)

切片

slice 只能和nil 进行==比较。

1
2
3
4
5
6
7
c := make([]int, 0)
fmt.Println(len(c), c == nil)
c = nil
fmt.Println(len(c), c == nil)
// Output:
// 0, false
// 0, true

结构体

Go没有类。然而,仍然可以在结构体类型上定义方法。
一个结构体(struct)就是一个字段的集合

一个命名为S的结构体类型将不能再包含S类型的成员

1
2
3
4
type S struct {
SS S // error: invalid recursive type S
II int
}

但是S类型的结构体可以包含*S指针类型的成员,这可以让我们创建递归的数据结构,比如链表和树结构等。

1
2
3
4
type S struct {
SS *S // ok
II int
}

匿名结构体中,
引用时可以直接访问子属性,而不需要给出完整的路径
但结构体字面值必须遵循形状类型声明时的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type Point struct {
但结构体字面值必须遵循形状类型声明时的结构
X, Y int
}

type Circle struct {
Center Point
Radius int
}

type Wheel struct {
Circle Circle
Spokes int
}

var w Wheel
w.X = 8 // equivalent to w.Circle.Point.X = 8
w.Y = 8 // equivalent to w.Circle.Point.Y = 8
w.Radius = 5 // equivalent to w.Circle.Radius = 5
w.Spokes = 20

// 但结构体字面值必须遵循形状类型声明时的结构
w = Wheel{8, 8, 5, 20} // compile error: unknown fields
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields

切片

1
b := a[:0]

可导出的

这个默认行为类似java中的public。
大写字母开头的变量是可导出的,也就是其它包可以读取的,是公有变量;小写字母开头的就是不可导出的,是私有变量。
大写字母开头的函数也是一样,相当于class中的带public关键词的公有函数;小写字母开头的就是有private关键词的私有函数。
http://go-tour-zh.appspot.com/basics/3

匿名字段

当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。
struct不仅仅能够将struct作为匿名字段、自定义类型、内置类型都可以作为匿名字段,而且可以在相应的字段上面进行函数操作

如果内层与继承层都有相同的字段,则:

  • 最外层优先访问; 例如:Bob.phone访问的是 Bob 层的字段
  • 可以通过匿名字段访问继承层;Bob.Human.phone 访问的是Human层的字段

方法

method是附属在一个给定的类型上的,他的语法和函数的声明语法几乎一样,只是在func后面增加了一个receiver(也就是method所依从的主体)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Rectangle struct {
width, height float64
}

type Circle struct {
radius float64
}

func (r Rectangle) area() float64 {
return r.width*r.height
}

func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}

在使用method的时候重要注意几点:

  • 虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样
  • method里面可以访问接收者的字段
  • 调用method通过.访问,就像struct里面访问字段一样

指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。

那是不是method只能作用在struct上面呢?当然不是咯,他可以定义在任何你自定义的类型、内置类型、struct等各种类型上面。这里你是不是有点迷糊了,什么叫自定义类型,自定义类型不就是struct嘛,不是这样的哦,struct只是自定义类型里面一种比较特殊的类型而已,还有其他自定义类型申明,可以通过如下这样的申明来实现。
type typeName typeLiteral

1
2
3
4
5
6
7
8
9
type ages int
type money float32
type months map[string]int
m := months {
"January":31,
"February":28,
...
"December":31,
}

函数作为值、类型

在Go中函数也是一种变量,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型
type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])
函数作为类型到底有什么好处呢?那就是可以把这个类型的函数当做值来传递

因此在Go语言里,我们为一些简单的数值、字符串、slice、map来定义一些附加行为很方便。
方法可以被声明到任意类型,只要不是一个指针或者一个interface。
https://yar999.gitbooks.io/gopl-zh/content/ch6/ch6-01.html

此外,为了避免歧义,在声明方法时,如果一个类型名本身是一个指针的话,是不允许其出现在接收器中的,比如下面这个例子:
https://yar999.gitbooks.io/gopl-zh/content/ch6/ch6-02.html

1
2
type P *int
func (P) f() { /* ... */ } // compile error: invalid receiver type

面向对象

  • 如果一个method的receiver是*T,你可以在一个T类型的实例变量V上面调用这个method,而不需要&V去调用这个method
  • 如果一个method的receiver是T,你可以在一个*T类型的变量P上面调用这个method,而不需要 *P去调用这个method

Go里面的面向对象是如此的简单,没有任何的私有、公有关键字,通过大小写来实现(大写开头的为公有,小写开头的为私有),方法也同样适用这个原则。

接口

interface在我们需要存储任意类型的数值的时候相当有用,因为他可以存储任意类型的数值。
神奇之处:在java中,必须现有interface,然后才有其继承类;而在go中,可以先有类,然后才有接口(当然,先有接口再有类更是可以的);https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.6.md
简单的说,interface是一组method 签名的组合,我们通过interface来定义对象的一组行为。

并行

  • 必须使用make来创建channel
  • goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
  • 我们可以看到go关键字很方便的就实现了并发编程。 上面的多个goroutine运行在同一个进程里面,共享内存数据,不过设计上我们要遵循:不要通过共享来通信,而要通过通信来共享。

    如何理解 Golang 中“不要通过共享内存来通信,而应该通过通信来共享内存”? - 知乎

  • runtime.Gosched()表示让CPU把时间片让给别人,下次某个时候继续恢复执行该goroutine。
  • make和new的区别 https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.2.md#makenew操作

    make用于内建类型(map、slice 和channel)的内存分配。new用于各种类型的内存分配。

    1. new返回指针。
      new(T)分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型T的零值。
    2. make返回初始化后的(非零)值。
      make只能创建slice、map和channel,并且返回一个有初始值(非零)的T类型,而不是*T。 在这些项目被初始化之前,slice为nil。
  • range和close

正则

注意:所有字符都是UTF-8处理。

字符串的处理可以使用strings包来进行搜索(Contains, Index)、替换(Replace)和解析(Split、Join)等操作

反射

[包]

当创建一个包,一般要用短小的包名,但也不能太短导致难以理解。
包名一般采用单数的形式。标准库的bytes、errors和strings使用了复数形式,这是为了避免和预定义的类型冲突,同样还有go/types是为了避免和type关键字冲突。
https://yar999.gitbooks.io/gopl-zh/content/ch10/ch10-06.html

0%