my-gitbook
Blog
  • 👨‍💻简介
  • 入门教程
    • markdown 入门教程
    • git 入门教程
      • 初识 git
        • 安装 git
        • 配置 git
      • 实战 git
        • 本地仓库
        • 版本管理
        • 回到过去
        • 基本概念
        • 版本控制
        • 撤销更改
        • 删除文件
        • 远程仓库
        • 分支管理
          • 分支总览
          • 冲突合并
          • 分支策略
          • 紧急修复
          • 变基合并
          • 协同开发
          • 本地和远程仓库的本质
        • 里程碑式标签
      • 私人定制
        • 忽略文件
        • 同步推送多Git仓库
      • 搭建私服
      • 扩展工具
        • git bash 常见命令
        • git bash 朋友圈
        • git bash 扩展tree命令
        • git bash 扩展命令(上)
        • git bash 扩展命令(中)
        • git bash 扩展命令(下)
        • git submodule 父子模块
      • 沙海拾贝
        • 知识速查
        • 备忘录[译]
    • github 入门教程
      • github 访问速度太慢
      • github 徽章从何而来
    • gitbook 入门教程
      • 准备阶段
        • 前置知识
        • 环境要求
      • 快速体验
        • gitbook-cli 命令行操作
        • gitbook-editor 编辑器操作
        • gitbook.com 官网操作
      • 高级进阶
        • 插件介绍
          • 实用插件
          • 主题插件
          • 开发插件
        • 导出电子书
        • 发布电子书
      • 公众号引流
      • 优化搜索
      • 常见问题
        • 热加载失败治标之法
        • 初始化默认折叠效果
      • 参考更多
  • 编程笔记
    • java 学习笔记
    • go 学习笔记
    • php 学习笔记
    • python 学习笔记
      • 入门教程
        • 00-ubuntu安装
        • 01-Linux基础
        • 操作系统的发展史(科普章节)
      • Django教程
        • Django 学习笔记
    • Linux 学习笔记
      • Linux基础
      • Linux全栈运维
  • 兴趣开发
    • 从零开始搭建服务器
      • 从登录服务器开始
      • 更加优雅地部署项目
      • 跟着官方体验 Docker
      • 快速尝鲜基于 Docker 部署项目
      • 利用阿里云 OSS部署静态网站
      • 免费实现https访问网站
      • webhook
    • 运维部署
      • docker 环境
      • docker 操作
      • docker compose
      • docker + nginx
      • docker + blog
      • docker + resume
      • docker + gitbook
      • docker + Bark
      • docker + py12306
      • docker + mojo-Weixin
      • docker + wechat-work-message-push-go
      • docker + email
      • docker + mysql
      • docker + springboot
      • docker + redis
      • docker + gogs
      • docker + gitlab
      • docker + gitea
      • docker + crawlab
    • 工具资源
      • 给 mac 装个 vmware 虚拟机
        • 给 mac 虚拟机装个 windows
        • 给 mac 虚拟机装个 centos
        • 给 mac 虚拟机装个 ubuntu
      • 给 windows 装个 vmware 虚拟机
        • 给 windows 虚拟机装个 mac
        • 给 windows 虚拟机装个 windows
        • 给 windows 虚拟机装个 centos
        • 给 windows 虚拟机装个 ubuntu
      • 公众号历史文章备份
        • Ryen
        • 苏生不惑
        • Python技术
      • 学会开发专属 chrome 插件
      • 攻克 12306 前端加密算法
    • 如何写作
      • markdown 和富文本
      • markdown 转富文本
      • csv 半手动数据统计
      • js 半手动数据统计
      • 简述优选文章统计
      • 快速上手Mermaid流程图
      • 常见问题
  • 读书观感
    • 大数据浪潮之巅:新技术商业制胜之道
  • 程序人生
    • 待完成清单
      • yarn快速入门
      • gulp快速入门
      • nvm快速入门
      • lodash快速入门
      • regexper快速入门
      • sublime快速入门
      • github 快速入门
      • svn 快速入门
      • java 快速入门
      • mysql 快速入门
      • maven 快速入门
      • tomcat 快速入门
      • gitignore 快速入门
      • android studio 快速入门
      • npm 快速入门
      • nginx 快速入门
    • 其他
      • 重装开发环境
      • 钉钉签到提醒
      • 倒计时提醒
      • 关注网站
      • 转型之路
      • 历史统计
      • 关于作者
      • 捐赠支持
由 GitBook 提供支持
在本页
  • TODO清单
  • 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
  • title: Hello World abbrlink: 16107
  • Reference
  • 错误管理
  • 资源管理与出错处理
  • defer 调用
  • 何时使用 defer 调用
  • 错误处理二
  • panic
  • recover
  • Go 的错误机制

这有帮助吗?

在GitHub上编辑
  1. 程序人生

待完成清单

上一页大数据浪潮之巅:新技术商业制胜之道下一页yarn快速入门

最后更新于1年前

这有帮助吗?

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


title: Hello World abbrlink: 16107

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) {
  // 「Ryen」: 正常顺序
  t.Log("「Ryen」: 正常顺序")

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

func TestFuncWithDefer(t *testing.T) {
  // 「Ryen」: 正常顺序执行完毕后才执行 defer 代码
  t.Log(" 「Ryen」: 正常顺序执行完毕后才执行 defer 代码")

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

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

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

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

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

func TestFuncWithMultipleDeferAndReturn(t *testing.T) {
  // 「Ryen」: defer 延迟函数会在包围函数正常return之前逆序执行.
  t.Log(" 「Ryen」: 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) {
  // 「Ryen」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.
  t.Log(" 「Ryen」: defer 延迟函数会在包围函数panic惊慌失措之前逆序执行.")

  // 3 2 1
  defer t.Log(1)
  defer t.Log(2)
  t.Log(3)
  panic("「Ryen」: 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:adsryen/private-cloud-backup.git 我们强烈建议所有的git仓库都有一个README, LICENSE, .gitignore文件

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

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

git config --global user.name "adsryen" git config --global user.email "adsryen@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:adsryen/private-cloud-backup.git git push -u origin master 已有仓库?

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

git remote --verbose
git remote set-url --add origin git@gitee.com:adsryen/adsryen.git
url = git@gitee.com:adsryen/adsryen.git
url = git@gitlab.com:adsryen/adsryen.gitlab.io.git
url = git@e.coding.net:adsryen/adsryen.coding.me.git
url = git@git.dev.tencent.com:adsryen/adsryen.git
```mind:height=300,title=a mind map of something,color
# 1
## 1.1
### 1.1.1
## 1.2
# 2
# 3
```

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

如何同步多个 git 远程仓库

nodejs-操作文件系统读取写入文件
10分钟教你撸一个nodejs爬虫系统
NodeJs+Request+Cheerio 采集数据
nodejs模拟登录-request模块
GitHub Wiki 页面的添加和设置
Kingfisher
Selenium 初探-Nodejs+Selenium环境搭建及基础用法
Selenium-webdriver基本使用
Selenium Web element
nodejs爬虫selenium
webhook 配置
Hexo
documentation
troubleshooting
GitHub
Hexo配置和部署
hexo——轻量、简易、高逼格的博客
5分钟搞定个人博客-hexo
hexo史上最全搭建教程
为Hexo添加Gitalk评论插件
Gitment/Gitalk自动初始化
自动初始化 Gitalk 和 Gitment 评论
Hexo+NexT(六):手把手教你编写一个Hexo过滤器插件
GitHub+Hexo搭建个人博客(四)Hexo高阶之第三方插件
搭建Hexo博客进阶篇--API和一些小部件(四)
Hexo高级教程之插件开发
Hexo主题开发
得到Go程序的汇编代码的方法
使用Hugo搭建静态站点
TOML简介
Hugo加入评论的功能
JS:SVG转图片的完美方法
js svg转图片格式 - Marydon - 博客园