Golang--包--fmt/time/flag/sort

本文详细介绍了Go语言中的包管理规范,包括包的创建、导入和可见性规则。接着深入讲解了fmt包的使用,如格式化输出、输入以及相关函数。接着探讨了time包的定时器功能,包括单次触发和时间间隔触发,并展示了如何进行时间操作。最后,介绍了sort包的排序机制,包括自定义排序接口和常见类型的便捷排序方法。
摘要由CSDN通过智能技术生成

写在最前:包package

  1. 一个文件夹下面只能有一个包,同样一个包的文件不能在多个文件夹下
  2. 包名可以不和文件夹的名字一样,包名不能包含-符号

如果想在一个包中已用另一个包中的标识符(变量、常量、类型、函数),该标识符必须是对外可见的(public)。在Go语言中将标识符的首字母大写就可以让标识符对外可见了

package pkg
import "fmt"

var a = 100 // 首字母小写,外部包不可见,只能在当前包内使用
const Mode = 1 // 首字母大写,外部包课件,可在其他包中使用

type person struct { // 首字母不可见
	name string
}

包内的init函数:无参数+无返回值

在GO语言中,导入包后会自动触发包内部的init()函数调用
init函数在程序运行时自动被调用执行,不能在代码中主动调用它
init函数的执行时机:全局声明 ==> init() ==> main()

1. fmt包

1.1. fmt 格式化输出

1.1.1. 打印输出: Print/Println/Printf

// 直接输出内容
func Print(a ...interface{}) (n int, err error)
// 直接输出内容,添加一个换行符
func Println(a ...interface{}) (n int, err error)
// 格式化输出
func Printf(format string, a ...interface{}) (n int, err error)

1.1.2. 输出到文件: Fprint/Fprintln/Fprintf

将内容输出到一个io.Writer接口类型的变量w中 ==> 通常用于向文件中写入内容

func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
// 向标准输出写入内容
fmt.Fprintln(os.Stdout, "向标准输出写入内容")
fileObj, err := os.OpenFile("./xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
	fmt.Println("打开文件出错,err:", err)
	return
}
name := "沙河小王子"
// 向打开的文件句柄中写入内容
fmt.Fprintf(fileObj, "往文件中写如信息:%s", name)

1.1.3. 格式化成字符串: Sprint/Sprintln/Sprintf

func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
s1 := fmt.Sprint("沙河小王子")
name := "沙河小王子"
age := 18
s2 := fmt.Sprintf("name:%s,age:%d", name, age)  // 格式化保存到字符串
s3 := fmt.Sprintln("沙河小王子")
fmt.Println(s1, s2, s3)

1.1.4. 格式化占位符

占位符说明
%v值的默认格式表示
%+v类似%v,但输出结构体时会添加字段名
%#v值的Go语法表示
%T打印值的类型
%%百分号
fmt.Printf("%v\n", 100)      // 100
fmt.Printf("%v\n", false)    // false

o := struct{ name string }{"小王子"}
fmt.Printf("%v\n", o)        // {小王子}
fmt.Printf("%#v\n", o)       // 转换为字符串: struct { name string }{name:"小王子"}
fmt.Printf("%T\n", o)        // 类型: struct { name string }
fmt.Printf("%%100\n")        // %100

1.2. fmt 获取输入

1.2.1. Scan/Scanln/Scanf

// 从“标准输入”中扫描用户输入的数据,将以“空白符”分隔的数据分别存入指定的参数
func Scan(a ...interface{}) (n int, err error)
// 类似于Scan,它在遇到换行符\n时才停止扫描 (最后一个数据后面必须有换行或者到达结束位置)
func Scanln(a ...interface{}) (n int, err error)
// 必须以format指定格式作为输入
func Scanf(format string, a ...interface{}) (n int, err error)

1.2.2. Fscan/Fscanln/Fscanf

从io.Reader中获取数据

func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)

1.2.3. Sscan/Sscanln/Sscanf

这几个函数功能分别类似于fmt.Scanfmt.Scanffmt.Scanln三个函数,只不过它们不是从标准输入中读取数据而是从指定字符串中读取数据。

func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)

1.2.4. bufio.NewReader

有时候我们想完整获取输入的内容,而输入的内容可能包含空格,这种情况下可以使用bufio包来实现:

func bufioDemo() {
	reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
	fmt.Print("请输入内容:")
	text, _ := reader.ReadString('\n')  // 获取输入,直到遇到\n才终止获取
	text = strings.TrimSpace(text)      // 移除string两端的空格
	fmt.Printf("%#v\n", text)
}

2. time包—定时器

定时器本质上是一个chan

2.1. 单次触发: NewTimer/After

package main

import (
	"fmt"
	"time"
)

func main() {
	// 用sleep实现定时器
	fmt.Println("[1] ", time.Now())
	time.Sleep(time.Second)
	fmt.Println("[2] ", time.Now())
	// 用timer实现定时器
	timer := time.NewTimer(time.Second)
	fmt.Println("[3] ", <-timer.C)
	// 用after实现定时器
	fmt.Println("[4] ", <-time.After(time.Second))
}

2.2. 时间间隔触发: time.Tick

案例:每间隔1s,定时器就会触发一次

// 方式1
func tickDemo() {
	ticker := time.Tick(time.Second) // 定义一个1s间隔的定时器
	for i := range ticker {  // for循环从通道ticker中读取
		fmt.Println(i)
	}
}
// 方式2
func main() {
    tiker := time.NewTicker(time.Second)  // 定义一个1s间隔的定时器
    for i := 0; i < 3; i++ {
        fmt.Println(<-tiker.C)
    }
}

2.3. Reset/Stop

重置定时器: timer.Reset(d Duration)
停止定时器:timer.Stop()

2.4. 关于time的其他API

参考链接

(1) 时间获取

  1. 获取当前时间:time.Now()

    package main
    import (
        "fmt"
        "time"
    )
    func main() {
        now := time.Now() //获取当前时间
        fmt.Printf("current time:%v\n", now) // // current time:2019-12-12 12:33:19.4712277 +0800 CST m=+0.006980401
        year := now.Year()     //年
        month := now.Month()   //月
        day := now.Day()       //日
        hour := now.Hour()     //小时
        minute := now.Minute() //分钟
        second := now.Second() //秒
        fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second) // // 2019-12-12 12:33:19
    }
    
  2. 获取时间戳

    • 时间戳是自 1970 年 1 月 1 日(08:00:00GMT)至当前时间的总毫秒数,它也被称为 Unix 时间戳(UnixTimestamp)
    package main
    import (
        "fmt"
        "time"
    )
    func main() {
        now := time.Now()                  //获取当前时间
        timestamp := now.Unix()            //时间戳
        timeObj := time.Unix(timestamp, 0) //将时间戳转为时间格式
        fmt.Println(timeObj)  // 2019-12-12 13:24:09 +0800 CST
        
        year := timeObj.Year()     //年
        month := timeObj.Month()   //月
        day := timeObj.Day()       //日
        hour := timeObj.Hour()     //小时
        minute := timeObj.Minute() //分钟
        second := timeObj.Second() //秒
        fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)    // 2019-12-12 13:24:09
    }
    

(2) 时间操作函数

  1. func (t Time) Add(d Duration) Time ==> 返回时间点 t + 时间间隔 d 的值
  2. func (t Time) Sub(u Time) Duration ==> 求两个时间之间的差值
  3. func (t Time) Equal(u Time) bool ==> 判断两个时间是否相同
  4. Before / After

3. flag包: 命令行参数解析

3.1. os.Args

如果你只是简单的想要获取命令行参数,可以像下面的代码示例一样使用os.Args来获取命令行参数。

package main

import (
	"fmt"
	"os"
)

func main() {
	if len(os.Args) > 0 {  //os.Args是一个[]string
		for index, arg := range os.Args {
			fmt.Printf("args[%d]=%v\n", index, arg)
		}
	}
}

执行结果,输入test.exe a b c d,输出见下

C:\Users\Sangfor\go\src\awesomeProject>test.exe a b c d
args[0]=test.exe
args[1]=a
args[2]=b
args[3]=c
args[4]=d

3.2. flag包: 可配参数案例

package main

import (
	"flag"
	"fmt"
	"time"
)

func main() {
	//定义变量用于接收flag
	var name string
	var age int
	var married bool
	var delay time.Duration

	// flag.[Type]Var(Type指针, flag名, 默认值, 帮助信息) : 获取输入的值
	//    &name变量(接收数据)  "name"(-name)  "张三"(缺省默认值)  "姓名"(描述信息)
	flag.StringVar(&name, "name", "张三", "姓名")
	flag.IntVar(&age, "age", 18, "年龄")
	flag.BoolVar(&married, "married", false, "婚否")
	flag.DurationVar(&delay, "d", 0, "延迟的时间间隔")

	/* 解析命令行参数
	      -flag xxx    使用空格,一个-符号
	      --flag xxx   使用空格,两个-符号
	      -flag=xxx    使用等号,一个-符号
	      --flag=xxx   使用等号,两个-符号
	 */
	flag.Parse()
	fmt.Println(name, age, married, delay) // 沙河娜扎 28 false 1h30m0s

	fmt.Println(flag.Args())    //返回命令行参数后的其他参数     []
	fmt.Println(flag.NArg())    //返回命令行参数后的其他参数个数  0
	fmt.Println(flag.NFlag())   //返回使用的命令行参数个数       4
}
/* 执行效果
$ test.exe -help
    Usage of ./flag_demo:
      -age int
            年龄 (default 18)
      -d duration
            时间间隔
      -married
            婚否
      -name string
            姓名 (default "张三")
            
>   test.exe  -married=false -d=1h30m --age 28 -name 沙河娜扎
    沙河娜扎 28 false 1h30m0s
    []
    0
    4
*/

4. sort包:排序

参考链接

  1. 前言

    ① sort 包内置的提供了根据一些排序函数来对任何序列排序的功能。它的设计非常独到。在很多语言中,排序算法都是和序列数据类型关联,同时排序函数和具体类型元素关联。

    ② 相比之下,Go语言的 sort.Sort 函数不会对具体的序列和它的元素做任何假设。相反,它使用了一个接口类型 sort.Interface 来指定通用的排序算法和可能被排序到的序列类型之间的约定。这个接口的实现由序列的具体表示和它希望排序的元素决定,序列的表示经常是一个切片。

  2. 一个内置的排序算法需要实现3个接口

    package sort
    type Interface interface {
        Len() int            // 获取元素长度
        Less(i, j int) bool  // 比较函数
        Swap(i, j int)       // 交换元素的方式
    }
    

    ​ 为了对序列排序,需要:①先定义一个类型,该类型实现了这3个方法;②定义该类型的实例对象obj,执行sort.Sort(obj)进行排序

    package main
    import (
        "fmt"
        "sort"
    )
    // 将[]string定义为MyStringList类型
    type MyStringList []string
    // 实现sort.Interface接口的3个方法
    func (m MyStringList) Len() int {
        return len(m)
    }
    func (m MyStringList) Less(i, j int) bool {
        return m[i] < m[j]
    }
    func (m MyStringList) Swap(i, j int) {
        m[i], m[j] = m[j], m[i]
    }
    func main() {
        // 准备一个内容被打乱顺序的字符串切片
        names := MyStringList{
            "3. Triple Kill",
            "5. Penta Kill",
            "2. Double Kill",
            "4. Quadra Kill",
            "1. First Blood",
        }
        // 使用sort包的Sort函数,将names(MyStringList类型)进行排序
        sort.Sort(names)
        // 遍历打印结果
        for _, v := range names {
                fmt.Printf("%s\n", v)
        }
    }
    /*
        1. First Blood
        2. Double Kill
        3. Triple Kill
        4. Quadra Kill
        5. Penta Kill
    */
    
  3. 常见类型的便捷排序

    GO中的sort包,提供了定制化的排序包,根据切片slice中的类型,如下

    ① slice元素类型:string

    • 方式1 ==> sort.Strings(a [] string)

      names := []string{    // 普通的字符串切片
          "3. Triple Kill",
          "5. Penta Kill",
          "2. Double Kill",
          "4. Quadra Kill",
          "1. First Blood",
      }
      sort.Strings(names)  // 使用 sort.Strings 直接对字符串切片进行排序。
      for _, v := range names {
          fmt.Printf("%s\n", v)
      }
      
    • 方式2 ==> sort.StringSlice

      sort 包中有一个 StringSlice 类型,定义如下:

      type StringSlice []string
      func (p StringSlice) Len() int           { return len(p) }
      func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
      func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
      // Sort is a convenience method.
      func (p StringSlice) Sort() { Sort(p) }
      

      使用案例

      names := sort.StringSlice{ // 使用sort.StringSlice创建结构体
          "3. Triple Kill",
          "5. Penta Kill",
          "2. Double Kill",
          "4. Quadra Kill",
          "1. First Blood",
      }
      sort.Sort(names)
      

    ② slice元素类型:整形 ==> sort.Ints(a []int) sort.Float64s(a []float64)

  4. 自定义结构体的排序 ==> sort.Slice

    ​ 从 Go 1.8 开始,Go语言在 sort 包中提供了 sort.Slice() 函数进行更为简便的排序方法。使用 sort.Slice() 不仅可以完成结构体切片排序,还可以对各种切片类型进行自定义排序。

    ​ sort.Slice() 函数只要求传入需要排序的数据,以及一个排序时对元素的回调函数,类型为 func(i,j int)bool,sort.Slice() 函数的定义如下:

    /* 
     * @param [in] slice  需要排序的切片
     * @param [in] less   回调函数:比较大小
     */
    func Slice(slice interface{}, less func(i, j int) bool)
    

    示例代码:sort.Slice

    package main
    import (
        "fmt"
        "sort"
    )
    type HeroKind int
    const (
        None = iota
        Tank
        Assassin
        Mage
    )
    type Hero struct {
        Name string
        Kind HeroKind
    }
    func main() {
    	/*
        	heros := Heros{
                &Hero{"吕布", Tank},
                &Hero{"诸葛亮", Mage},
            }        
        */
        heros := []*Hero{  // 准备英雄列表
            {"吕布", Tank},
            {"诸葛亮", Mage},
        }
        sort.Slice(heros, func(i, j int) bool {
            if heros[i].Kind != heros[j].Kind {
                return heros[i].Kind < heros[j].Kind
            }
            return heros[i].Name < heros[j].Name
        })
        for _, v := range heros {
            fmt.Printf("%+v\n", v)
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值