待完成清单

TODO清单

$ npm version patch
$ git tag
$ git push origin v0.0.2
$ npm install -g cnpm --registry=https://registry.npm.taobao.org

https://johnnyting.github.io/posts/%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4%E5%BF%AB%E9%80%9F%E7%94%9F%E6%88%90readmegitignore%E6%96%87%E4%BB%B6/

readme

https://github.com/kefranabg/readme-md-generator

  • https://github.com/github/gitignore/

  • http://www.gitignore.io/

"engines": {
    "gitbook": ">=2.4.3"
  },
  "gitbook": {
    "properties": {
      "blogId": {
        "type": "string",
        "required": true,
        "description": "Openwrite blogId."
      },
      "name": {
        "type": "string",
        "required": true,
        "description": "Blog name."
      },
      "qrcode": {
        "type": "string",
        "required": true,
        "description": "Wechat qrcode."
      },
      "keyword": {
        "type": "string",
        "required": true,
        "description": "Wechat keyword."
      }
    }
  }

INFO Install dependencies npm WARN deprecated core-js@1.2.7: core-js@<2.6.8 is no longer maintained. Please, upgrade to core-js@3 or at least to actual version of core-js@2. npm ERR! code EACCES npm ERR! syscall open npm ERR! path /Users/sunpo/.npm/_cacache/index-v5/51/d3/7697273802dffa158119427da833e251b88e0e9d4c73d8f5f964476884f4 npm ERR! errno -13 npm ERR! npm ERR! Your cache folder contains root-owned files, due to a bug in npm ERR! previous versions of npm which has since been addressed. npm ERR! npm ERR! To permanently fix this problem, please run: npm ERR! sudo chown -R 501:20 "/Users/sunpo/.npm"

npm ERR! A complete log of this run can be found in: npm ERR! /Users/sunpo/.npm/_logs/2019-10-09T01_40_58_136Z-debug.log WARN Failed to install dependencies. Please run 'npm install' manually!

sunpodeMacBook-Pro:hexo-plugin-readmore sunpo$ sudo chown -R 501:20 "/Users/sunpo/.npm" Password: sunpodeMacBook-Pro:hexo-plugin-readmore sunpo$ npm install npm notice created a lockfile as package-lock.json. You should commit this file. up to date in 1.429s found 0 vulnerabilities


Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Reference

32dc4ab0f6b98922dcada02d9b6cd8da4bcb1935

错误管理

资源管理与出错处理

defer 调用

  • 确保调用在函数结束时发生

  • 参与在defer语言时计算

  • defer列表为后进先出

何时使用 defer 调用

  • Open/Close

  • Lock/Unlock

  • PrintHeader/PrintFooter

错误处理二

  • 如何实现统一的错误处理逻辑

panic

  • 停止当前函数执行

  • 一直向上返回,执行每一层的 defer

  • 如果没有遇见recover,程序退出

recover

  • 仅在 defer 调用中使用

  • 获取 panic 的值

  • 如果无法处理,可重新 panic

error vs panic

  • 意料之中的:使用 error,如: 文件打不开

  • 意料之外的:使用 panic,如: 数组越界

Go 的错误机制

与其他主要的编程语言的差异:

  • 没有异常机制

  • error 类型实现了 error 接口

  • 可以通过 errors.New 来快速创建错误实例

type error interface{
    Error() string
}

errors.New("n must be in the range []")

panic

  • panic 用于不可恢复的错误

  • panic 退出前会执行defer指定的内容

panic vs os.Exit

  • os.Exit 退出时不会调用 defer指定的函数

  • os.Exit 退出时不输出当前调用栈信息

当心,recover 称为恶魔

  • 形成僵尸服务进程,导致 health check 失效

  • "Let it Crash" 往往是我们恢复不确定性错误的最好方式

https://golang.google.cn/ref/spec#Defer_statements

A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.

defer Stmt = "defer" Expression .
func TestFuncWithoutDefer(t *testing.T) {
  // 「雪之梦技术驿站」: 正常顺序
  t.Log("「雪之梦技术驿站」: 正常顺序")

  // 1 2
  t.Log(1)
  t.Log(2)
}

func TestFuncWithDefer(t *testing.T) {
  // 「雪之梦技术驿站」: 正常顺序执行完毕后才执行 defer 代码
  t.Log(" 「雪之梦技术驿站」: 正常顺序执行完毕后才执行 defer 代码")

  // 2 1
  defer t.Log(1)
  t.Log(2)
}

func TestFuncWithMultipleDefer(t *testing.T) {
  // 「雪之梦技术驿站」: 猜测 defer 底层实现数据结构可能是栈,先进后出.
  t.Log(" 「雪之梦技术驿站」: 猜测 defer 底层实现数据结构可能是栈,先进后出.")

  // 3 2 1
  defer t.Log(1)
  defer t.Log(2)
  t.Log(3)
}

func TestFuncWithMultipleDeferOrder(t *testing.T) {
  // 「雪之梦技术驿站」: defer 底层实现数据结构类似于栈结构,依次倒叙执行多个 defer 语句
  t.Log(" 「雪之梦技术驿站」: defer 底层实现数据结构类似于栈结构,依次倒叙执行多个 defer 语句")

  // 2 3 1
  defer t.Log(1)
  t.Log(2)
  defer t.Log(3)
}

func TestFuncWithMultipleDeferAndReturn(t *testing.T) {
  // 「雪之梦技术驿站」: defer 延迟函数会在包围函数正常return之前逆序执行.
  t.Log(" 「雪之梦技术驿站」: defer 延迟函数会在包围函数正常return之前逆序执行.")

  // 3 2 1
  defer t.Log(1)
  defer t.Log(2)
  t.Log(3)
  return
  t.Log(4)
}

func TestFuncWithMultipleDeferAndPanic(t *testing.T) {
  // 「雪之梦技术驿站」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.
  t.Log(" 「雪之梦技术驿站」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.")

  // 3 2 1
  defer t.Log(1)
  defer t.Log(2)
  t.Log(3)
  panic("「雪之梦技术驿站」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.")
  t.Log(4)
}

The expression must be a function or method call; it cannot be parenthesized. Calls of built-in functions are restricted as for expression statements.

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed.

注意2:defer函数参数的计算时间点 defer函数的参数是在defer语句出现的位置做计算的,而不是在函数运行的时候做计算的,即所在函数结束的时候计算的。

package main

import "log"

func foo(n int) int {
    log.Println("n1=", n)
    defer log.Println("n=", n)
    n += 100
    log.Println("n2=", n)
    return n
}

func main() {
    var i int = 100
    foo(i)
}

其运行结果是:

2017/09/30 19:25:10 n1= 100 2017/09/30 19:25:10 n2= 200 2017/09/30 19:25:10 n= 100 可以看到defer函数的位置时n的值为100,尽管在函数foo结束的时候n的值已经是200了,但是defer语句本身所处的位置时刻,即foo函数入口时n为100,所以最终defer函数打印出来的n值为100。

注意3:如何在defer语句里面使用多条语句

前面我们提到defer后面只能是一条函数调用指令;而实际情况下经常会需要逻辑运行,会有分支,条件,而不是简单的一个log.Print指令;那怎么处理这种情况呢,我们可以把这些逻辑指令一起定义成一个函数,然后再调用这些函数就行了,命名函数或者匿名函数都可以,下面是一个匿名函数的例子:

package main

import "log" import _ "time"

func foo(n int) int { log.Println("n1=", n) defer func() { n += 100 log.Println("n=", n) }() n += 100 log.Println("n2=", n) return n }

func main() { var i int = 100 foo(i) } 运行结果:

2017/09/30 19:30:58 n1= 100 2017/09/30 19:30:58 n2= 200 2017/09/30 19:30:58 n= 300 眼尖的同学会发现其中的问题;为什么n打印出来是300呢,不是明明说好defer函数的参数值在它出现时候计算,而不是在运行的时候计算的吗,n应该打印出200才对啊? 同学,仔细看一下原文:defer函数的参数在defer语句出现的位置计算,不是在defer函数运行的时刻计算;人家明明说的很清楚,defer函数的参数,请问这里n是参数吗,不是哎,这里引用的是宿主函数的局部变量,而不是参数;所以它拿到的是运行时刻的值。

这就引发出下一个注意事项。

注意4:defer函数会影响宿主函数的返回值 package main

import "log"

func foo1(i *int) int { *i += 100 defer func() { *i += 200 }() log.Printf("i=%d", *i) return *i }

func foo2(i *int) (r int) { *i += 100 defer func() { r += 200 }() log.Printf("i=%d", *i) return *i }

func main() { var i, r int

i,r = 0,0
r = foo1(&i)
log.Printf("i=%d, r=%d\n", i, r)

i,r = 0,0
r = foo2(&i)
log.Printf("i=%d, r=%d\n", i, r)

} 运行结果为:

$ go build main.go && ./main 2017/09/30 20:01:00 i=100 2017/09/30 20:01:00 i=300, r=100 2017/09/30 20:01:00 i=100 2017/09/30 20:01:00 i=100, r=300 这个例子其实有一点拗口的。 foo1 return指令前(i==100, ret==0),return指令后(i==100, ret=100),然后调用defer函数后(i==300,r==100),defer函数增加了i;main函数收到(i==300, r==100) foo2 return指令前(i==100, ret==0),return指令后(i==100, ret=100),然后调用defer函数后(i==100,r==300),defer函数增加了ret;main函数收到(i==100, r==300)

因为如果defer后面的f.Close()没有延迟执行,那么文件描述符都关闭了,就不会读取到任何内容。

函数值和函数参数被求值,但函数不会立即调用 下面这个例子即将诠释上半段,它来自<>,稍作修改:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func trace(funcName string) func(){ start := time.Now() fmt.Printf("function %s enter\n",funcName) return func(){ log.Printf("function %s exit (elapsed %s)",funcName,time.Since(start)) } }

func foo(){ defer trace("foo()")() time.Sleep(5time.Second) } func main(){ foo() foo() } / OUTPUT: function foo() enter function foo() exit (elapsed 5.0095471s) function foo() enter function foo() exit (elapsed 5.0005382s) */   

为什么foo会输出enter然后等待五秒左右再输出exit? 因为正如我们说的,

defer后面的函数值和参数会被求值但是实际函数调用却要等到最后

这里函数值就是trace()返回的匿名函数,函数参数当然就是字符串字面值"foo()", 对trace("foo()")的求值会输出function foo() enter, 实际函数调用trace("foo()")()即输出function foo() exit(elapsed x.x)会推迟到return执行(如果return会更新返回值变量,则会在更新后才执行defer的函数)。

快速设置— 如果你知道该怎么操作,直接使用下面的地址

git@gitee.com:snowdreams1006/private-cloud-backup.git 我们强烈建议所有的git仓库都有一个README, LICENSE, .gitignore文件

Git入门?查看 帮助 , Visual Studio / TortoiseGit / Eclipse / Xcode 下如何连接本站, 如何导入仓库

简易的命令行入门教程: Git 全局设置:

git config --global user.name "snowdreams1006" git config --global user.email "snowdreams1006@163.com" 创建 git 仓库:

mkdir private-cloud-backup cd private-cloud-backup git init touch README.md git add README.md git commit -m "first commit" git remote add origin git@gitee.com:snowdreams1006/private-cloud-backup.git git push -u origin master 已有仓库?

cd existing_git_repo git remote add origin git@gitee.com:snowdreams1006/private-cloud-backup.git git push -u origin master

git remote --verbose
git remote set-url --add origin git@gitee.com:snowdreams1006/snowdreams1006.git
url = git@gitee.com:snowdreams1006/snowdreams1006.git
url = git@gitlab.com:snowdreams1006/snowdreams1006.gitlab.io.git
url = git@e.coding.net:snowdreams1006/snowdreams1006.coding.me.git
url = git@git.dev.tencent.com:snowdreams1006/snowdreams1006.git
```mind:height=300,title=a mind map of something,color
# 1
## 1.1
### 1.1.1
## 1.2
# 2
# 3
```
snowdreams1006@192 snowdreams1006.github.io % gitbook serve 
Live reload server started on port: 35729
Press CTRL+C to quit ...

/Users/snowdreams1006/.nvm/versions/node/v12.18.3/lib/node_modules/gitbook-cli/node_modules/npm/node_modules/graceful-fs/polyfills.js:287
      if (cb) cb.apply(this, arguments)
                 ^

TypeError: cb.apply is not a function
    at /Users/snowdreams1006/.nvm/versions/node/v12.18.3/lib/node_modules/gitbook-cli/node_modules/npm/node_modules/graceful-fs/polyfills.js:287:18
    at FSReqCallback.oncomplete (fs.js:169:5)
  // fs.stat = statFix(fs.stat)
  // fs.fstat = statFix(fs.fstat)
  // fs.lstat = statFix(fs.lstat)

Last updated