Go语言命令行利器cobra使用教程cobra是一个提供简单接口来创建强大的现代CLI界面的库类似gitgit tools,cobra也是一个应用程序,它会生成你的应用程序的脚手架来快速开发基于cobra的应用程序
cobra提供:
cobra建立在命令、参数、标志的结构之上
commands代表动作,args是事物,flags是动作的修饰符
最好的应用程序在使用时读起来就像句子,因此,用户直观地知道如何与它们交互
模式如下:APPNAME VERB NOUN --ADJECTIVE. or APPNAME COMMAND ARG --FLAG(APPNAME 动词 名词 形容词 或者 APPNAME 命令 参数 标志)
一些真实世界的好例子可以更好地说明这一点
kubectl 命令更能体现APPNAME 动词 名词 形容词
如下的例子,server 是command,port是flag
这个命令中 , 我们告诉git 克隆url
命令是应用程序的中心点,应用程序支持的每一个交互都包含在一个命令中,命令可以有子命令,也可以运行操作
在上面的例子中,server是命令
更多关于cobra.Command
flag是一种修改命令行为的方式,cobra支持完全兼容POSIX标志,也支持go flag package , cobra可以定义到子命令上的标志,也可以仅对该命令可用的标志
在上面的命令中,port是标志
标志的功能由 pflag library 提供 , pflag library是flag标准库的一个分支,在添加POSIX兼容性的同时维护相同的接口 。
使用cobra很简单 , 首先 , 使用go get按照最新版本的库 , 这个命令会安装cobra可执行程序以及库和依赖项
下一步,引入cobra到应用程序中
虽然欢迎您提供自己的组织,但通常基于Cobra的应用程序将遵循以下组织结构:
在Cobra应用程序中,main.go文件通常非常简单 。它有一个目的:初始化Cobra 。
使用cobra生成器
cobra提供了程序用来创建你的应用程序然后添加你想添加的命令,这是将cobra引入应用程序最简单的方式
这儿 你可以发现关于cobra的更多信息
要手动实现cobra , 需要创建一个main.go 和rootCmd文件,可以根据需要提供其他命令
Cobra不需要任何特殊的构造器 。只需创建命令 。
理想情况下,您可以将其放在app/cmd/root.go中:
在init()函数中定义标志和处理配置
例子如下,cmd/root.go:
创建main.go
使用root命令,您需要让主函数执行它 。为清楚起见,Execute应该在根目录下运行 , 尽管它可以在任何命令上调用 。
在Cobra应用程序中,main.go文件通常非常简单 。它有一个目的:初始化Cobra 。
可以定义其他命令,通常每个命令在cmd/目录中都有自己的文件 。
如果要创建版本命令,可以创建cmd/version.go并用以下内容填充它:
如果希望将错误返回给命令的调用者,可以使用RunE 。
然后可以在execute函数调用中捕获错误 。
标志提供修饰符来控制操作命令的操作方式 。
由于标志是在不同的位置定义和使用的,因此我们需要在外部定义一个具有正确作用域的变量来分配要使用的标志 。
有两种不同的方法来分配标志 。
标志可以是“持久”的 , 这意味着该标志将可用于分配给它的命令以及该命令下的每个命令 。对于全局标志,在根上指定一个标志作为持久标志 。
也可以在本地分配一个标志,该标志只应用于该特定命令 。
默认情况下,Cobra只解析目标命令上的本地标志,而忽略父命令上的任何本地标志 。通过启用Command.TraverseChildren , Cobra将在执行目标命令之前解析每个命令上的本地标志 。
使用viper绑定标志
在本例中,持久标志author与viper绑定 。注意:当用户未提供--author标志时,变量author将不会设置为config中的值 。
更多关于 viper的文档
Flags默认是可选的,如果希望命令在未设置标志时报告错误 , 请根据需要进行标记:
持久性Flags
可以使用命令的Args字段指定位置参数的验证 。
内置了以下验证器:
在下面的示例中 , 我们定义了三个命令 。两个是顶级命令,一个(cmdTimes)是顶级命令之一的子命令 。在这种情况下,根是不可执行的,这意味着需要一个子命令 。这是通过不为“rootCmd”提供“Run”来实现的 。
我们只为一个命令定义了一个标志 。
有关标志的更多文档,请访问
对于一个更完整的例子更大的应用程序,请检查 Hugo。
当您有子命令时,Cobra会自动将help命令添加到应用程序中 。当用户运行“应用程序帮助”时,将调用此函数 。此外,help还支持所有其他命令作为输入 。例如,您有一个名为“create”的命令,没有任何附加配置;调用“app help create”时,Cobra将起作用 。每个命令都会自动添加“-help”标志 。
以下输出由Cobra自动生成 。除了命令和标志定义之外,不需要任何东西 。
帮助就像其他命令一样 。它周围没有特殊的逻辑或行为 。事实上 , 你可以提供你想提供的 。
您可以为默认命令提供自己的帮助命令或模板,以用于以下功能:
当用户提供无效的标志或无效的命令时,Cobra通过向用户显示“用法”来响应 。
你可以从上面的帮助中认识到这一点 。这是因为默认帮助将用法作为其输出的一部分嵌入 。
您可以提供自己的使用函数或模板供Cobra使用 。与帮助一样 , 函数和模板也可以通过公共方法重写:
如果在root命令上设置了version字段 , Cobra会添加一个顶级的'--version'标志 。运行带有“-version”标志的应用程序将使用版本模板将版本打印到标准输出 。可以使用cmd.SetVersionTemplate(s string)函数自定义模板 。
可以在命令的主运行函数之前或之后运行函数 。PersistentPreRun和PreRun函数将在运行之前执行 。PersistentPostRun和PostRun将在运行后执行 。如果子函数不声明自己的函数,则它们将继承Persistent*Run函数 。这些函数按以下顺序运行:
输出:
当发生“未知命令”错误时,Cobra将打印自动建议 。这使得Cobra在发生拼写错误时的行为类似于git命令 。例如:
基于注册的每个子命令和Levenshtein距离的实现,建议是自动的 。匹配最小距离2(忽略大小写)的每个已注册命令都将显示为建议 。
如果需要在命令中禁用建议或调整字符串距离,请使用:
or
您还可以使用SuggestFor属性显式设置将为其建议给定命令的名称 。这允许对在字符串距离方面不接近的字符串提供建议,但在您的一组命令中是有意义的,并且对于某些您不需要别名的字符串 。例子:
Cobra可以基于子命令、标志等生成文档 。请在 docs generation文档 中阅读更多关于它的信息 。
Cobra可以为以下shell生成shell完成文件:bash、zsh、fish、PowerShell 。如果您在命令中添加更多信息,这些补全功能将非常强大和灵活 。在 Shell Completions 中阅读更多关于它的信息 。
Cobra is released under the Apache 2.0 license. SeeLICENSE.txt
golang获取到string和直接赋值strimg不一样1、 string的定义
Golang中的string的定义在reflect包下的value.go中,定义如下:
StringHeader 是字符串的运行时表示 , 其中包含了两个字段,分别是指向数据数组的指针和数组的长度 。
// StringHeader is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
Data uintptr
Lenint
}
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
2、string不可变
Golang中的字符串是不可变的,不能通过索引下标的方式修改字符串中的数据:
在这里插入图片描述
运行代码,可以看到编译器报错,string是不可变的
在这里插入图片描述
但是能不能进行一些骚操作来改变元素的值呢?
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
a := "hello,world"
b := a[6:]
bptr := (*reflect.StringHeader) (unsafe.Pointer(b))
fmt.Println(a)
fmt.Println(b)
【go语言execute的简单介绍】 *(*byte)(unsafe.Pointer(bptr.Data)) = '.'
fmt.Println(a)
fmt.Println(b)
}
// 运行结果
hello,world
world
unexpected fault address 0x49d7e3
fatal error: fault
[signal 0xc0000005 code=0x1 addr=0x49d7e3 pc=0x4779fa]
goroutine 1 [running]:
runtime.throw(0x49c948, 0x5)
C:/Program Files/Go/src/runtime/panic.go:11170x79 fp=0xc0000dbe90 sp=0xc0000dbe60 pc=0x405fd9
runtime.sigpanic()
C:/Program Files/Go/src/runtime/signal_windows.go:2450x2d6 fp=0xc0000dbee8 sp=0xc0000dbe90 pc=0x4189f6
main.main()
F:/go_workspace/src/code/string_test/main.go:200x13a fp=0xc0000dbf88 sp=0xc0000dbee8 pc=0x4779fa
runtime.main()
C:/Program Files/Go/src/runtime/proc.go:2250x256 fp=0xc0000dbfe0 sp=0xc0000dbf88 pc=0x4087f6
runtime.goexit()
C:/Program Files/Go/src/runtime/asm_amd64.s:13710x1 fp=0xc0000dbfe8 sp=0xc0000dbfe0 pc=0x435da1
Process finished with the exit code 2
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
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
在上面的代码中,因为在go语言中不能进行指针的加减运算,因此取切片,让b的Data指针指向’,'所在的位置 。然后把"hello,world"中的逗号改为点,但是发现还是不行,程序直接崩溃了 。看来go语言中的指针得到了大大的限制,设计者并不想让程序员过度使用指针来写出一些不安全的代码 。
3、使用string给另一个string赋值
Golang中的字符串的赋值并不是拷贝底层的字符串数组,而是数组指针和长度字段的拷贝 。例如:当我们定义了一个字符串 a := “hello,world” 然后定义了 b := a 底层所做的操作只是创建了两个StringHeader的结构体,它们的Data字段都指向同一段数据,如下图:
在这里插入图片描述
我们可以利用代码来证实这一点:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
a := "hello,world"
b := a
fmt.Println(a)
fmt.Println(b)
aptr := (*reflect.StringHeader) (unsafe.Pointer(a))
bptr := (*reflect.StringHeader) (unsafe.Pointer(b))
fmt.Println("a ptr:", unsafe.Pointer(aptr.Data))
fmt.Println("b ptr:", unsafe.Pointer(bptr.Data))
}
// 运行结果
hello, world
hello, world
a ptr: 0x6bdb76
b ptr: 0x6bdb76
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
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
在上面的代码中,将a和b转换为StringHeader类型的指针,然后分别打印出,a和b的Data指针的值,发现是相同的
那么如果对a做切片赋值给b呢?
func main() {
a := "hello,world"
b := a[6:]
fmt.Println(a)
fmt.Println(b)
aptr := (*reflect.StringHeader) (unsafe.Pointer(a))
bptr := (*reflect.StringHeader) (unsafe.Pointer(b))
fmt.Println("a ptr:", unsafe.Pointer(aptr.Data))
fmt.Println("b ptr:", unsafe.Pointer(bptr.Data))
}
// 运行结果
hello,world
world
a ptr: 0xd4d849
b ptr: 0xd4d84f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0xd4d849 - 0xd4d84f = 0x000006
显然 , 也没有分配新的数组并拷贝数据,而是将原字符数组的指针的偏移赋给了b的StringHeader的Data
4、string重新赋值
如果对一个已经赋值的字符串重新赋值 , 也不会修改原内存空间,而是申请了新的内存空间 , 对其赋值,并指向新的内存空间 。如下图:
在这里插入图片描述
也可以使用代码来证实一下:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
a := "hello,world"
aptr := (*reflect.StringHeader) (unsafe.Pointer(a))
fmt.Println("a ptr:", unsafe.Pointer(aptr.Data))
fmt.Println("a len", aptr.Len)
a = "hello,golang"
newAPtr := (*reflect.StringHeader) (unsafe.Pointer(a))
fmt.Println("b ptr:", unsafe.Pointer(newAPtr.Data))
fmt.Println("b len:", newAPtr.Len)
}
// 运行结果
a ptr: 0x3ed7f4
a len 11
b ptr: 0x3edb2c
b len: 12
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
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
文章知识点与官方知识档案匹配
Go技能树九阴真经字符串
2043 人正在系统学习中
点击阅读全文
打开CSDN APP,看更多技术内容
Golang底层原理剖析之string类型与字符编码_cheems~的博客_g...
string类型 string结构 go语言中默认使用的是UTF-8编码 string由两部分组成,一部分是指向字符串起始地址的指针,另一部分是字节个数len注意不是字符个数,是字节个数!这个数据类型占用16B空间,指向字符串起始地址的指针和存在字节个数的整...
继续访问
...底层系列二(基础)_GoGo在努力的博客_golang string底层
1、 string的定义 Golang中的string的定义在reflect包下的value.go中,定义如下: StringHeader 是字符串的运行时表示,其中包含了两个字段,分别是指向数据数组的指针和数组的长度 。// StringHeader is the runtime representation of a...
继续访问
最新发布 Golang: []string 和 ...string
… 参数语法形成了可变参数的参数 。它将接受零个或多个string参数,并将它们作为切片引用
继续访问
常用的Golang字符串(string)操作
文章目录Golang中常用的字符串操作一、标准库相关的Package二、常用字符串操作判断是否为空字符串 正文 Golang中常用的字符串操作 一、标准库相关的Package 二、常用字符串操作 判断是否为空字符串 思路:直接判断是否等于""空字符串,由于golang中字符串不能为nil,且为值类型,所以直接与空字符串比较即可 举例: str := "" if str == ""{...
继续访问
golang中的string_xiaodongdonga的博客_golang ...string
golang中的string 在golang中,string其实是个结构体,如图 ,在这个结构体中有两个值,一个是指向字符数组的指针str,另一个是这个字符串的长度len 。另外在golang中用的是UFT8边长编码,里面字母是用一个字节,西方的文字使用两个字节,...
继续访问
Golang中对字符串string的相关操作_Codex_97的博客_go 字符...
golang中拥有string的内置类型,可以使用与普通slice类型相似的性质 。1.简介 strings包提供了很多操作字符串的简单函数,通常一般的字符串操作都可以在这个包中找到 。strconv 包提供了基本数据类型和字符串之间的转换 。在Go 中,没有隐式...
继续访问
go-string-set:一种在GoLang中创建字符串集的方法
概述 通过字符串设置方法 。用法 go get github.com/wojnosystems/go-string-set package main import ( "github.com/wojnosystems/go-string-set/string_set" "strings" ) func main () { myPeople := string_set . New () myPeople . Add ( "Bob" ) myPeople . Add ( "Jane" ) myPeople . Add ( "Gary" ) myPeople . Add ( "Bob" ) if myPeople . Exists ( "Bob" ) { // Bob exists in myPeople, so this code block execute
Golang:strings包和字符串操作
strings包 string类型值是不可变的,如果想要获得一个不一样的字符串,就只能基于原字符串进行剪裁 , 拼接等操作,然后将得到的新字符串存放到一块联系内存中 。string值包含了指向底层字节数组头部的指针值,以及该字节数组的长度 。在string值上做切片,就相当于在其底层字节数组做切片 。而字符串拼接时(使用 ) , 会把所有被拼接的字符串依次拷贝到一个崭新且足够大的连续内存空间中,并把持有新...
继续访问
golang中的strings.SplitN_盼盼编程的博客_strings.splitn
golang中的字符串操作strings.SplitN package main import ( "fmt" "strings" ) //golang字符串操作 func main(){ s := "hello world hello world" //str := "wo" //以str为分隔符,将s切分成多个子串,结果中**不包含*...
继续访问
Golang_String常用操作_itzhuzhu.的博客_golang strings
func main() { var x string = "ITzhuzhu" var y string = "itzhuzhu" fmt.Println(strings.EqualFold(x, y)) //true fmt.Println(x == y) //false } 1 2 3 4 5 6 返回子串在字符串第一次出现的索引,如果没有则...
继续访问
Golang类型的String()方法
作用 用于定制fmt.Println(x)、fmt.Printf("%v", x)、fmt.Print(x)时输出的内容 。示例 package main import "fmt" type Couple struct { Husband string Wife string } func (self Couple) String() string { return "(husband:"self.Husband", wife:"self.Wife
继续访问
golang的string
golang中的string是不可变的字节序列,零值是空字符串 , 默认是UTF-8编码 。golang中使用字符串最需要注意的是,golang中的字符串是字节序列,string == []byte,由于一个字符占用的字节数不确定,所以无法通过下标[i]的方式稳定地获取对应位置的字符 。也就意味着字符串的第i个字节 , 不一定就是第i个字符,原因请参考 unicode与UTF-8 文字符号在golang中被称为rune,发音为/ru:n/,意思是符号 。由于utf-8最多使用4个字节来编码,所以rune类型是int3
继续访问
golang中的strings.Trim_盼盼编程的博客_strings.trim
golang中的字符串操作strings.Trim package main import ( "fmt" "strings" ) //golang字符串操作 func main(){ s := "Hello world hello world" str := "world" //var s = []string{"11","22","33"} //删除s首尾...
继续访问
Golang 字符串
Go语言的代码是由Unicode字符组成的,它们都必须由Unicode编码规范中的UTF-8编码格式进行编码并存储,Unicode编码规范中的编码格式定义的是字符与字节序列之间的转换方式 。其中的UTF-8是一种可变宽的编码方案,它会用一个或多个字节的二进制数来表示某个字符,最多使用四个字节 。Go语言中的一个string类型值会由若干个Unicode字符组成,每个Unicode字符都可以由一个rune类型的值来承载 。stringforrange 。...
继续访问
golang字符串[]string(slice)去重
1、现实代码 // []string 去重 func RemoveDuplicate(list []string) []string { // 这个排序很关键 sort.Strings(list) i := 0 var newlist = []string{""} for j := 0; jlen(list); j{ if strings.Compare(newlist[i], list[j]) == -1 { newlist = append(newlist, lis
继续访问
深入理解golang string
golang string string的定义 // string is the set of all strings of 8-bit bytes, conventionally but not // necessarily representing UTF-8-encoded text. A string may be empty, but // not nil. Values of string type are immutable. type string string string里存储的是字符
继续访问
golang中string包
对于基本类型来说,字符串所需要执行的操作会比较复杂,所以一般语言都会额外封装一些方法用于处理字符串 , go语言标准库中也存在这样一个名为strings的库 包含判断,判断一个字符中是否有相应的某个子字符串是经常遇到的一种字符串操作,再go语言中可以使用strings包中的两个方法判断 ...
继续访问
golang中的strings.TrimLeft
golang中的字符串操作strings.TrimLeft package main import ( "fmt" "strings" ) //golang字符串操作 func main(){ s := "Hello world hello world" str := "Hello" //var s = []string{"11","22","33"} //删除s头部连续的包含在str中的字符串 .
继续访问
golang入门time与string转换, time加减时间, 两个时间差
package mainimport ( "fmt" "time")var timeLayoutStr = "2006-01-02 15:04:05" //go中的时间格式化必须是这个时间//var timeLayoutStr = 2006/01/02 03:04:05 //合法, 格式可以改变//var timeLayoutStr = 2019/01/02 15:04:05 /...
继续访问
Golang——string
1.string结构体底层 由两部分组成:指向底层[ ]byte数组的指针;长度(类似切片结构体) 2.相同的string常量不会重复存储 //由s1、s2的指针指向一块相同的只读内存 , 这段内存以utf-8编码存放hello数组 s1 := "hello" s2 := "hello" 3.string常量会在编译期分配到只读段,对应数据地址不可写入,故string不支持修改 。要修改必须转[]byte , string和[]byte转换,会将这段只读内存的数据复制到堆/栈上 。//wrong s := "he
继续访问
热门推荐 golang -----------字符串(rune,string,type)
一、内存布局 字符串在Go语言内存模型中用一个2字长的数据结构表示 。它包含一个指向字符串存储数据的指针和一个长度数据 。因为string类型是不可变的,对于多字符串共享同一个存储数据是安全的 。切分操作str[i:j]会得到一个新的2字长结构,一个可能不同的但仍指向同一个字节序列(即上文说的存储数据)的指针和长度数据 。这意味着字符串切分可以在不涉及内存分配或复制操作 。这使得字符串切分的效率等同于...
继续访问
Golang string 常用方法
strings.Compare(p1, p2) 判断p1是否大于p2,大于:1,小于:-1,等于:0 。2.strings.LastIndex(p1,p2) p2在p1中最后一次出现的位置,未出现返回-1 。1.strings.Replace(p1,p2,p3,n) 将p1中的p2替换成p3,最多替换n个 。1.strings.Index(p1,p2) p2在p1中第一次出现的位置,未出现返回-1 。2.strings.ReplaceAll(p1,p2,p3) 将p1中的所有p2替换成p3 。
继续访问
golang中的字符串
在go中rune是一个unicode编码点 。我们都知道UTF-8将字符编码为1-4个字节,比如我们常用的汉字,UTF-8编码为3个字节 。所以rune也是int32的别名 。
继续访问
golang之字符串
Go语言的字符有两种类型: 一种是byte型,或者叫uint8类型,代表了ASCII码的一个字符 。一种是rune类型,或者叫int32类型,代表一个UTF-8字符 , 当需要处理中文、日文等unicode字符时,则需要用到rune类型 。...
继续访问
Golang的 string 类型
一点睛 字符串就是一串固定长度的字符连接起来的字符序列 。Go 的字符串是由单个字节连接起来的 。Go语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本 。二 string 使用注意事项和细节 1 Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本,这样 Golang 统一使用 UTF-8 编码,中文乱码问题不会再困扰程序员 。2 字符串一旦赋值了,字符串就不能修改了,在 Go 中字符串是不可变的 。3 字符串的两种表示形式 。a 双引号——会识别转义字符 .
继续访问
Golang Strings 官方包常用方法,学会这些够用了
1.判断是否以某字符串打头/结尾 2.字符串分割 3.返回子串索引 4.字符串连接 5.字符串转化为大小写 6.统计某个字符在字符串出现的次数 7.判断字符串的包含关系 8.字符串替换
各位大佬VC中bulidexecute和go的区别是什么?用C语言从编写源码 , 到运行一个程序的过程,可以概括为:
编写源代码(edit)- 编译(compile)- 连接,也叫生成(build)- 运行(execute) 。
build:在汇编里称link,在C里叫build,它的作用是生成可执行的exe文件 。由于一个程序的源码可由多个文件组成 。这些文件在第二步中分别编译,生成各自的目标文件(*.obj),这一步的作用便是将这些obj文件,以及程序中需要的其它库文件(dll除开),统一到一个文件中来,形成单个的exe文件 。此exe文件便可以在操作系统下直接运行了 。
excute:运行,不同的情况下意义也不同 。
1.程序有修改时,或者没有做前面的编译连接工作时
execute=compile+build+运行 。在VC中一般快截键是ctrlF5 。
2.程序编译连接成功后
execute仅仅是执行程序,不再做前面两项工作 。
关于go语言execute和的介绍到此就结束了 , 不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。
推荐阅读
- 长虹彩电怎么连接硬盘,长虹液晶电视怎么连接dvd参考图
- 中继路由器怎么安装到电视,无线路由中继器怎么安装
- 火山视频可以拍摄什么电影,火山视频现在拍视频还可以赚钱吗
- vb.net右键菜单 vba右键菜单
- 电商如何联系物流,做电商怎么跟物流合作
- 动作类打丧尸游戏有哪些,丧尸动作玩家
- mysql命令怎么弄出来 如何使用mysql命令界面
- 怎么查看显卡上市日期时间,怎么查看显卡什么时候生产的
- 换电脑系统需要做什么备份,换系统电脑原来的东西会没有吗