提交 04c228d8 编写于 作者: 写代码的明哥's avatar 写代码的明哥

update

上级 769a00f6
......@@ -6,7 +6,7 @@
0. 什么是结构体?
-----------------
在之前学过的数据类型中,数组与切片,只能存储同一类型的变量。若要存储多个类型的变量,就需要用到结构体,它是将多个容易类型的命令变量组合在一起的聚合数据类型。
在之前学过的数据类型中,数组与切片,只能存储同一类型的变量。若要存储多个类型的变量,就需要用到结构体,它是将多个任意类型的变量组合在一起的聚合数据类型。
每个变量都成为该结构体的成员变量。
......@@ -102,7 +102,7 @@ self,在方法内可以使用 ``person.属性名`` 的方法来访问实例属
3. 方法的参数传递方式
---------------------
上面定义方法的方式叫当你想要在方法内改变实例的属性的时候,必须使用指针做为方法的接收者。
当你想要在方法内改变实例的属性的时候,必须使用指针做为方法的接收者。
.. code:: go
......@@ -132,7 +132,7 @@ self,在方法内可以使用 ``person.属性名`` 的方法来访问实例属
}
输出结果 如下,可以看到在方法内部对 age 的修改已经生效。你可以尝试去掉
``*``\ ,使用值做为方法接收者,看看age是否会发生改变
``*``\ ,使用值做为方法接收者,看看age是否会发生改变(答案是:不会改变)
::
......
......@@ -50,12 +50,14 @@
在官方文档中,make 函数的描述如下
//The make built-in function allocates and initializes an object //of
type slice, map, or chan (only). Like new, the first argument is // a
type, not a value. Unlike new, make’s return type is the same as //
the type of its argument, not a pointer to it.
::
func make(t Type, size …IntegerType) Type
//The make built-in function allocates and initializes an object
//of type slice, map, or chan (only). Like new, the first argument is
// a type, not a value. Unlike new, make's return type is the same as
// the type of its argument, not a pointer to it.
func make(t Type, size ...IntegerType) Type
翻译一下注释内容
......@@ -64,7 +66,7 @@
2. make
返回类型的本身而不是指针,而返回值也依赖于具体传入的类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
注意,因为这三种类型是引用类型,所以必须得初始化(size和cap),但不是置为零值,这个和new是不一样的。
注意,因为这三种类型是引用类型,所以必须得初始化(size和cap),但不是置为零值,这个和new是不一样的。
举几个例子
......
......@@ -172,7 +172,7 @@ func main() {
fmt.Printf("接收到的数据是: %d", num)
}()
// 主函数sleep,使得上面两个goroutine有机会执行
time.Sleep(1)
time.Sleep(time.Second)
}
```
......@@ -248,7 +248,7 @@ func main() {
fmt.Printf("接收到的数据是: %d", num)
}()
// 主函数sleep,使得上面两个goroutine有机会执行
time.Sleep(1)
time.Sleep(time.Second)
}
```
......@@ -297,10 +297,10 @@ func main() {
```go
package main
import {
import (
"fmt"
"time"
}
)
// 由于 x=x+1 不是原子操作
// 所以应避免多个协程对x进行操作
......@@ -322,7 +322,7 @@ func main() {
// 确保所有的协程都已完成
// 以后会介绍一种更合适的方法(Mutex),这里暂时使用sleep
time.Sleep(3)
time.Sleep(time.Second)
fmt.Println("x 的值:", x)
}
```
......
......@@ -173,7 +173,7 @@ int 等等)
fmt.Printf("接收到的数据是: %d", num)
}()
// 主函数sleep,使得上面两个goroutine有机会执行
time.Sleep(1)
time.Sleep(time.Second)
}
**单向信道**
......@@ -244,7 +244,7 @@ int 等等)
fmt.Printf("接收到的数据是: %d", num)
}()
// 主函数sleep,使得上面两个goroutine有机会执行
time.Sleep(1)
time.Sleep(time.Second)
}
5. 遍历信道
......@@ -292,10 +292,10 @@ range关键字,在range时,要确保信道是处于关闭状态,否则循
package main
import {
import (
"fmt"
"time"
}
)
// 由于 x=x+1 不是原子操作
// 所以应避免多个协程对x进行操作
......@@ -317,7 +317,7 @@ range关键字,在range时,要确保信道是处于关闭状态,否则循
// 确保所有的协程都已完成
// 以后会介绍一种更合适的方法(Mutex),这里暂时使用sleep
time.Sleep(3)
time.Sleep(time.Second)
fmt.Println("x 的值:", x)
}
......
......@@ -3,8 +3,8 @@
|image0|
\ `19. 学习 Go
协程:详解信道/通道 <http://mp.weixin.qq.com/s?__biz=MzU1NzU1MTM2NA==&mid=2247483741&idx=1&sn=4d4ccd8fdee404432f03447927ddb055&chksm=fc355b36cb42d2201e12b77085f7db5a5fed98674e369a5df7fd852abde09a1efad35ba28944&scene=21#wechat_redirect>`__\ 」这一节里我详细地介绍信道的一些用法,要知道的是在
\ `4.3 学习 Go
协程:详解信道/通道 <http://golang.iswbm.com/en/latest/c04/c04_03.html>`__\ 」这一节里我详细地介绍信道的一些用法,要知道的是在
Go 语言中,信道的地位非常高,它是 first class
级别的,面对并发问题,我们始终应该优先考虑使用信道,如果通过信道解决不了的,不得不使用共享内存来实现并发编程的,那
Golang 中的锁机制,就是你绕不过的知识点了。
......
......@@ -2,7 +2,46 @@
![](http://image.iswbm.com/20200607145423.png)
## 参数种类
在 Golang 程序中有很多种方法来处理命令行参数。
简单的情况下可以不使用任何库,直接使用 `os.Args`
```go
package main
import (
"fmt"
"os"
)
func main() {
//os.Args是一个[]string
if len(os.Args) > 0 {
for index, arg := range os.Args {
fmt.Printf("args[%d]=%v\n", index, arg)
}
}
}
```
试着运行一下,第一个参数是执行文件的路径。
```shell
$ go run demo.go hello world hello golang
args[0]=/var/folders/72/lkr7ltfd27lcf36d75jdyjr40000gp/T/go-build187785213/b001/exe/demo
args[1]=hello
args[2]=world
args[3]=hello
args[4]=golang
```
从上面你可以看到,`os.Args` 只能处理简单的参数,而且对于参数的位置有严格的要求。对于一些比较复杂的场景,就需要你自己定义解析规则,非常麻烦。
如果真的遇上了所谓的复杂场景,那么还可以使用 Golang 的标准库 flag 包来处理命令行参数。
本文将介绍 Golang 标准库中 flag 包的用法。
## 1. 参数种类
根据参数是否为布尔型,可以分为两种:
......@@ -14,7 +53,7 @@
- 长参数:比如 `--name jack` 就是一个长参数,参数名前有两个 `-`
- 短参数:通常为一个或两个字母(是对应长参数的简写),比如 `-n` ,参数名前只有一个 `-`
## 入门示例
## 2. 入门示例
我先用一个字符串类型的参数的示例,抛砖引玉
......@@ -45,11 +84,14 @@ flag.Parse() // 解析参数
运行以上程序,输出如下
```go
$ go run demo.go
jack
$ go run demo.go --name wangbm
wangbm
```
## 改进一下
## 3. 改进一下
如果你的程序只接收很少的几个参数时,上面那样写也没有什么问题。
......@@ -77,7 +119,7 @@ func main(){
}
```
## 参数类型
## 4. 参数类型
当你在命令行中指定了参数,Go 如何解析这个参数,转化成何种类型,是需要你事先定义的。
......@@ -107,6 +149,7 @@ func main(){
```shell
$ go run main.go
false
$ go run main.go --debug
true
```
......@@ -133,6 +176,7 @@ func main(){
```shell
$ go run main.go
18
$ go run main.go --age 20
20
```
......@@ -161,6 +205,7 @@ func main(){
```shell
$ go run main.go
jack
$ go run main.go --name wangbm
wangbm
```
......@@ -191,9 +236,13 @@ $ go run main.go --interval 2s
2s
```
## 自定义类型
## 5. 自定义类型
flag 包支持的类型有 Bool、Duration、Float64、Int、Int64、String、Uint、Uint64。
另外,还可以创建自定义flag,只要 Var 函数的第一个参数对象实现 flag.Value接口即可
这些类型的参数被封装到其对应的后端类型中,比如 Int 类型的参数被封装为 intValue,String 类型的参数被封装为 stringValue。
这些后端的类型都实现了 flag.Value 接口,因此可以把一个命令行参数抽象为一个 Flag 类型的实例。下面是 Value 接口和 Flag 类型的代码:
```go
type Value interface {
......@@ -201,19 +250,49 @@ type Value interface {
Set(string) error
}
// Flag 类型
type Flag struct {
Name string // name as it appears on command line
Usage string // help message
Value Value // value as set 是个 interface,因此可以是不同类型的实例。
DefValue string // default value (as text); for usage message
}
func Var(value Value, name string, usage string) {
CommandLine.Var(value, name, usage)
}
```
假如我想实现这样一个效果
想要实现自定义类型的参数,其实只要 Var 函数的第一个参数对象实现 flag.Value接口即可
```go
type sliceValue []string
func newSliceValue(vals []string, p *[]string) *sliceValue {
*p = vals
return (*sliceValue)(p)
}
func (s *sliceValue) Set(val string) error {
// 如何解析参数值
*s = sliceValue(strings.Split(val, ","))
return nil
}
func (s *sliceValue) String() string {
return strings.Join([]string(*s), ",")
}
```
比如我想实现如下效果,传入的参数是一个字符串,以逗号分隔,flag 的解析时将其转成 slice。
```shell
$ go run demo.go -members "Jack,Tom"
[Jack Tom]
```
我可以这样子编写代码
我可以这样子编写代码
```go
var members []string
......@@ -248,9 +327,9 @@ func main(){
有的朋友 可能会对 `(*sliceValue)(p)` 这行代码有所疑问,这是什么意思呢?
关于这个,其实之前在 【http://golang.iswbm.com/en/latest/c02/c02_09.html#id2】有讲过,忘记了可以前往复习。
关于这个,其实之前在 【[2.9 详细图解:静态类型与动态类型](http://golang.iswbm.com/en/latest/c02/c02_09.html#id2)】有讲过,忘记了可以前往复习。
## 长短选项
## 6. 长短选项
flag 包,在使用上,其实并没有没有长短选项之别,你可以看下面这个例子
......@@ -302,6 +381,14 @@ exit status 2
## 7. 总结一下
flag 在绝大多数场景下,它是够用的,但如果要支持更多的命令传入格式,flag 可能并不是最好的选择。
那些在标准库不能解决的场景,往往会有相应的Go爱好者提供第三方解决方案。我所了解到的 cobra 就是一个非常不错的库。
它能够支持 flag 不能支持的功能,比如 **支持短选项****支持子命令** 等等,后面找个机会再好好写一下。
## flag 的函数
### Lookup
......@@ -314,14 +401,6 @@ m := flag.Lookup("members")
## go-flags
flag 内置库有一些不足的地方
- 不显示支持短选项。
- 选项变量的定义比较繁琐,每个选项都需要根据类型调用对应的`Type``TypeVar`函数;
- 默认只支持有限的数据类型,当前只有基本类型`bool/int/uint/string``time.Duration`
![](http://image.iswbm.com/20200607174235.png)
\ No newline at end of file
......@@ -3,8 +3,49 @@
|image0|
参数种类
--------
Golang 程序中有很多种方法来处理命令行参数。
简单的情况下可以不使用任何库,直接使用 ``os.Args``
.. code:: go
package main
import (
"fmt"
"os"
)
func main() {
//os.Args是一个[]string
if len(os.Args) > 0 {
for index, arg := range os.Args {
fmt.Printf("args[%d]=%v\n", index, arg)
}
}
}
试着运行一下,第一个参数是执行文件的路径。
.. code:: shell
$ go run demo.go hello world hello golang
args[0]=/var/folders/72/lkr7ltfd27lcf36d75jdyjr40000gp/T/go-build187785213/b001/exe/demo
args[1]=hello
args[2]=world
args[3]=hello
args[4]=golang
从上面你可以看到,\ ``os.Args``
只能处理简单的参数,而且对于参数的位置有严格的要求。对于一些比较复杂的场景,就需要你自己定义解析规则,非常麻烦。
如果真的遇上了所谓的复杂场景,那么还可以使用 Golang 的标准库 flag
包来处理命令行参数。
本文将介绍 Golang 标准库中 flag 包的用法。
1. 参数种类
-----------
根据参数是否为布尔型,可以分为两种:
......@@ -19,8 +60,8 @@
- 短参数:通常为一个或两个字母(是对应长参数的简写),比如 ``-n``
,参数名前只有一个 ``-``
入门示例
--------
2. 入门示例
-----------
我先用一个字符串类型的参数的示例,抛砖引玉
......@@ -52,11 +93,14 @@
.. code:: go
$ go run demo.go
jack
$ go run demo.go --name wangbm
wangbm
改进一下
--------
3. 改进一下
-----------
如果你的程序只接收很少的几个参数时,上面那样写也没有什么问题。
......@@ -86,8 +130,8 @@
fmt.Println(name)
}
参数类型
--------
4. 参数类型
-----------
当你在命令行中指定了参数,Go
如何解析这个参数,转化成何种类型,是需要你事先定义的。
......@@ -121,6 +165,7 @@ false,你一指定 ``--debug``\ ,debug 为赋值为 true。
$ go run main.go
false
$ go run main.go --debug
true
......@@ -148,6 +193,7 @@ false,你一指定 ``--debug``\ ,debug 为赋值为 true。
$ go run main.go
18
$ go run main.go --age 20
20
......@@ -178,6 +224,7 @@ UintVar、Float64Var 方法,也是同理,不再赘述。
$ go run main.go
jack
$ go run main.go --name wangbm
wangbm
......@@ -208,11 +255,18 @@ UintVar、Float64Var 方法,也是同理,不再赘述。
$ go run main.go --interval 2s
2s
自定义类型
----------
5. 自定义类型
-------------
另外,还可以创建自定义flag,只要 Var 函数的第一个参数对象实现
flag.Value接口即可
flag 包支持的类型有
BoolDurationFloat64IntInt64StringUintUint64
这些类型的参数被封装到其对应的后端类型中,比如 Int 类型的参数被封装为
intValueString 类型的参数被封装为 stringValue
这些后端的类型都实现了 flag.Value
接口,因此可以把一个命令行参数抽象为一个 Flag 类型的实例。下面是 Value
接口和 Flag 类型的代码:
.. code:: go
......@@ -221,18 +275,50 @@ flag.Value接口即可
Set(string) error
}
// Flag 类型
type Flag struct {
Name string // name as it appears on command line
Usage string // help message
Value Value // value as set 是个 interface,因此可以是不同类型的实例。
DefValue string // default value (as text); for usage message
}
func Var(value Value, name string, usage string) {
CommandLine.Var(value, name, usage)
}
假如我想实现这样一个效果
想要实现自定义类型的参数,其实只要 Var 函数的第一个参数对象实现
flag.Value接口即可
.. code:: go
type sliceValue []string
func newSliceValue(vals []string, p *[]string) *sliceValue {
*p = vals
return (*sliceValue)(p)
}
func (s *sliceValue) Set(val string) error {
// 如何解析参数值
*s = sliceValue(strings.Split(val, ","))
return nil
}
func (s *sliceValue) String() string {
return strings.Join([]string(*s), ",")
}
比如我想实现如下效果,传入的参数是一个字符串,以逗号分隔,flag
的解析时将其转成 slice
.. code:: shell
$ go run demo.go -members "Jack,Tom"
[Jack Tom]
我可以这样子编写代码
我可以这样子编写代码
.. code:: go
......@@ -268,11 +354,11 @@ flag.Value接口即可
有的朋友 可能会对 ``(*sliceValue)(p)``
这行代码有所疑问,这是什么意思呢?
关于这个,其实之前在
http://golang.iswbm.com/en/latest/c02/c02_09.html#id2】有讲过,忘记了可以前往复习。
关于这个,其实之前在 \ `2.9
详细图解:静态类型与动态类型 <http://golang.iswbm.com/en/latest/c02/c02_09.html#id2>`__\ 】有讲过,忘记了可以前往复习。
长短选项
--------
6. 长短选项
-----------
flag 包,在使用上,其实并没有没有长短选项之别,你可以看下面这个例子
......@@ -322,6 +408,18 @@ flag 包,在使用上,其实并没有没有长短选项之别,你可以看
你的名字 (default "明哥")
exit status 2
7. 总结一下
-----------
flag 在绝大多数场景下,它是够用的,但如果要支持更多的命令传入格式,flag
可能并不是最好的选择。
那些在标准库不能解决的场景,往往会有相应的Go爱好者提供第三方解决方案。我所了解到的
cobra 就是一个非常不错的库。
它能够支持 flag 不能支持的功能,比如 **支持短选项**\ \ **支持子命令**
等等,后面找个机会再好好写一下。
flag 的函数
-----------
......@@ -334,15 +432,6 @@ Lookup
m := flag.Lookup("members")
go-flags
--------
flag 内置库有一些不足的地方
- 不显示支持短选项。
- 选项变量的定义比较繁琐,每个选项都需要根据类型调用对应的\ ``Type``\ \ ``TypeVar``\ 函数;
- 默认只支持有限的数据类型,当前只有基本类型\ ``bool/int/uint/string``\ \ ``time.Duration``\
|image1|
.. |image0| image:: http://image.iswbm.com/20200607145423.png
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册