go程序语言设计ch1---echo

程序一:输出其命令行参数

//echo 输出其命令行参数

package main

import (
   "fmt"
   "os"
   "strings"
)

func echo1(){
   var s,sep string
   for i:=1;i<len(os.Args);i++{
      s+=sep+os.Args[i]
      sep = " "
   }
   fmt.Println(s)
}

func echo2(){
   s,sep := "",""
   for _,arg := range os.Args[1:]{
      s += sep + arg
      sep = " "
   }
   fmt.Println(s)
}

func echo3(){
   fmt.Println(strings.Join(os.Args[1:]," "))
}

1.Go字符串连接

对于字符串的连接大致有两种方式:
1、通过+号连接

func StrPlus1(a []string) string {
	var s, sep string
	for i := 0; i < len(a); i++ {
		s += sep + a[i]
		sep = " "
	}
	return s
}

2、通过strings.Join连接

func StrPlus2(a []string) string {
	return strings.Join(a, " ")
}

对比两种方式的效率,通过压力测试进行对比

import "testing"

func BenchmarkStrPlus1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		StrPlus1([]string{"xxx", "bbb", "aaa"})
	}
}

func BenchmarkStrPlus2(b *testing.B) {
	for i := 0; i < b.N; i++ {
		StrPlus2([]string{"xxx", "bbb", "aaa"})
	}
}

运行压力测试go test -test.bench=".*"

goos: darwin
goarch: amd64
BenchmarkStrPlus1-4     10000000               127 ns/op
BenchmarkStrPlus2-4     20000000                78.7 ns/op

从本机来看通过+号连接字符串每个操作消耗127ns时间,strings.Join消耗78.7ns。效率上strings.Join更高

来看下strings包中Join的实现

// Join concatenates the elements of a to create a single string. The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
	switch len(a) {
	case 0:
		return ""
	case 1:
		return a[0]
	case 2:
		// Special case for common small values.
		// Remove if golang.org/issue/6714 is fixed
		return a[0] + sep + a[1]
	case 3:
		// Special case for common small values.
		// Remove if golang.org/issue/6714 is fixed
		return a[0] + sep + a[1] + sep + a[2]
	}
    //n为计算sep与命令行参数总共所需字节数
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := copy(b, a[0])
	for _, s := range a[1:] {
		bp += copy(b[bp:], sep)
		bp += copy(b[bp:], s)
	}
	return string(b)
}

可以看出当连接字符串数量较大时,是先通过make分配足够的空间,然后把每个字符串copy到空间里面,而不是每次通过+号来多次分配内存。

2.命令行参数

1. os.args
func main () {
   for idx, args := range os.Args {
      fmt.Println("参数",idx,":",args)
   }
}

运行结果如下:

image-20220226112605331

os.Args是一个存储命令行参数的字符串切片,它的第一个元素是执行文件的名称。

2. flag包

flag包支持的命令行参数类型有bool、int、int64、uint、uint64、float float64、string、duration。

flag参数有效值
字符串flag合法字符串
整数flag1234、0664、0x1234等类型,也可以是负数。
浮点数flag合法浮点数
bool类型flag1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False。
时间段flag任何合法的时间段字符串。如”300ms”、”-1.5h”、”2h45m”。 合法的单位有”ns”、”us” /“µs”、”ms”、”s”、”m”、”h”。

1. flag.Type(flag名, 默认值, 帮助信息)*Type

func main() {    
// 第一个参数是命令行key,第二个参数是默认是,第三个参数是 .exe -h 提示    
var user = flag.String("user""root""用户名")    
var port = flag.Int("port"3306"端口")    
var ip = flag.String("ip""localhost""mysql ip")
    //必须使用flag.Parse()解析一下命令行参数    
flag.Parse()    //flag.Type返回的是一个指针,必须通过 *变量取值    
fmt.Println(*user,*port,*ip)
}

2. flag.TypeVar(Type指针, flag名, 默认值, 帮助信息)

flag.Type返回的是指针。需要用*变量才能取到值。

var name string
var age int
var married bool
var delay time.Duration
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.DurationVar(&delay, "d", 0, "时间间隔")

通过以上两种方法定义好命令行flag参数后,需要通过调用flag.Parse()来对命令行参数进行解析。

支持的命令行参数格式有以下几种:

  • -flag xxx (使用空格,一个-符号)
  • –flag xxx (使用空格,两个-符号)
  • -flag=xxx (使用等号,一个-符号)
  • –flag=xxx (使用等号,两个-符号)

其中,布尔类型的参数必须使用等号的方式指定。

Flag解析在第一个非flag参数(单个”-“不是flag参数)之前停止,或者在终止符”–“之后停止。

3.其他函数

  • flag.Args() 返回命令行参数后的其他参数,以[]string类型
  • flag.NArg() //返回命令行参数后的其他参数个数
  • flag.NFlag() //返回使用的命令行参数个数
func main() {
    //定义命令行参数方式1
    var name string
    var age int
    var married bool
    var delay time.Duration
    flag.StringVar(&name, "name", "张三", "姓名")
    flag.IntVar(&age, "age", 18, "年龄")
    flag.BoolVar(&married, "married", false, "婚否")
    flag.DurationVar(&delay, "d", 0, "延迟的时间间隔")

    //解析命令行参数
    flag.Parse()
    fmt.Println(name, age, married, delay)
    //返回命令行参数后的其他参数
    fmt.Println(flag.Args())
    //返回命令行参数后的其他参数个数
    fmt.Println(flag.NArg())
    //返回使用的命令行参数个数
    fmt.Println(flag.NFlag())
}

命令行参数使用提示:

    $ ./flag_demo -help
    Usage of ./flag_demo:
      -age int
            年龄 (default 18)
      -d duration
            时间间隔
      -married
            婚否
      -name string
            姓名 (default "张三")

正常使用命令行flag参数:

    $ ./flag_demo -name pprof --age 28 -married=false -d=1h30m
    pprof 28 false 1h30m0s
    []
    0
    4

使用非flag命令行参数:

    $ ./flag_demo a b c
    张三 18 false 0s
    [a b c]
    3
    0

    $ ./flag_demo -name pprof --age 28 -married=false -d=1h30m
    pprof 28 false 1h30m0s
    []
    0
    4

使用非flag命令行参数:

    $ ./flag_demo a b c
    张三 18 false 0s
    [a b c]
    3
    0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值