Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
go开源项目镜像
GolangCodingTime
提交
04c228d8
G
GolangCodingTime
项目概览
go开源项目镜像
/
GolangCodingTime
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
GolangCodingTime
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
04c228d8
编写于
2月 27, 2021
作者:
写代码的明哥
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update
上级
769a00f6
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
236 addition
and
66 deletion
+236
-66
source/c02/c02_01.rst
source/c02/c02_01.rst
+3
-3
source/c02/c02_10.rst
source/c02/c02_10.rst
+8
-6
source/c04/c04_03.md
source/c04/c04_03.md
+5
-5
source/c04/c04_03.rst
source/c04/c04_03.rst
+5
-5
source/c04/c04_05.rst
source/c04/c04_05.rst
+2
-2
source/c05/c05_03.md
source/c05/c05_03.md
+97
-18
source/c05/c05_03.rst
source/c05/c05_03.rst
+116
-27
未找到文件。
source/c02/c02_01.rst
浏览文件 @
04c228d8
...
...
@@ -6,7 +6,7 @@
0.
什么是结构体?
-----------------
在之前学过的数据类型中,数组与切片,只能存储同一类型的变量。若要存储多个类型的变量,就需要用到结构体,它是将多个
容易类型的命令
变量组合在一起的聚合数据类型。
在之前学过的数据类型中,数组与切片,只能存储同一类型的变量。若要存储多个类型的变量,就需要用到结构体,它是将多个
任意类型的
变量组合在一起的聚合数据类型。
每个变量都成为该结构体的成员变量。
...
...
@@ -102,7 +102,7 @@ self,在方法内可以使用 ``person.属性名`` 的方法来访问实例属
3.
方法的参数传递方式
---------------------
上面定义方法的方式叫
当你想要在方法内改变实例的属性的时候,必须使用指针做为方法的接收者。
当你想要在方法内改变实例的属性的时候,必须使用指针做为方法的接收者。
..
code
::
go
...
...
@@ -132,7 +132,7 @@ self,在方法内可以使用 ``person.属性名`` 的方法来访问实例属
}
输出结果
如下,可以看到在方法内部对
age
的修改已经生效。你可以尝试去掉
``*``\
,使用值做为方法接收者,看看
age
是否会发生改变
。
``*``\
,使用值做为方法接收者,看看
age
是否会发生改变
(答案是:不会改变)
::
...
...
source/c02/c02_10.rst
浏览文件 @
04c228d8
...
...
@@ -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是不一样的。
举几个例子
...
...
source/c04/c04_03.md
浏览文件 @
04c228d8
...
...
@@ -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
)
}
```
...
...
source/c04/c04_03.rst
浏览文件 @
04c228d8
...
...
@@ -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
)
}
...
...
source/c04/c04_05.rst
浏览文件 @
04c228d8
...
...
@@ -3,8 +3,8 @@
|
image0
|
在
「
\
`
19.
学习
Go
协程:详解信道
/
通道
<
http
://
mp
.
weixin
.
qq
.
com
/
s
?
__biz
=
MzU1NzU1MTM2NA
==&
mid
=
2247483741
&
idx
=
1
&
sn
=
4
d4ccd8fdee404432f03447927ddb055
&
chksm
=
fc355b36cb42d2201e12b77085f7db5a5fed98674e369a5df7fd852abde09a1efad35ba28944
&
scene
=
21
#
wechat_redirect
>`
__
\
」这一节里我详细地介绍信道的一些用法,要知道的是在
在
「
\
`
4.3
学习
Go
协程:详解信道
/
通道
<
http
://
golang
.
iswbm
.
com
/
en
/
latest
/
c04
/
c04_03
.
html
>`
__
\
」这一节里我详细地介绍信道的一些用法,要知道的是在
Go
语言中,信道的地位非常高,它是
first
class
级别的,面对并发问题,我们始终应该优先考虑使用信道,如果通过信道解决不了的,不得不使用共享内存来实现并发编程的,那
Golang
中的锁机制,就是你绕不过的知识点了。
...
...
source/c05/c05_03.md
浏览文件 @
04c228d8
...
...
@@ -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
source/c05/c05_03.rst
浏览文件 @
04c228d8
...
...
@@ -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
2
s
2
s
自定义类型
----------
5.
自定义类型
----------
---
另外,还可以创建自定义
flag
,只要
Var
函数的第一个参数对象实现
flag
.
Value
接口即可
flag
包支持的类型有
Bool
、
Duration
、
Float64
、
Int
、
Int64
、
String
、
Uint
、
Uint64
。
这些类型的参数被封装到其对应的后端类型中,比如
Int
类型的参数被封装为
intValue
,
String
类型的参数被封装为
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录