go实践k-v存储系统| 青训营笔记

81 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天

基于go的map,实现了一个极其极其极其极其极其极其简易的CRUD系统.支持4种数据操作,2种其他操作:

  • 增 ADD
  • 删 DELETE
  • 改 CHANGE
  • 查 LOOKUP
  • PRINT:打印所有存储数据
  • STOP:优雅退出

非常简短,项目结构就是一个小main.go. 源码分析如下:

数据结构

使用原生的Go map来实现K-V存储,因为内置的数据结构往往执行效率更高。map变量被声明为全局变量,其k为string类型,v为myElement类型,myElement是自定义的结构体。

type myElement struct {
	Name    string
	SurName string
	Id      string
}

var DATA = make(map[string]myElement)

数据操作

这部分代码实现了命令行ADDDELETE,用户在执行ADD命令时,如果没有携带足够的参数,我们要保证该操作不会失败,意味着myElement中对应的字段为空字符串。然而如果你要添加的key已经存在了,就会报错(K-V存储不允许重复key出现)而不是修改对应的值。 该代码段实现了LOOKUPCHANGE功能,如果你要修改的key不存储,程序会自动将其存储。 PRINT命令能够打印出目前所有K-V存储的内容。

func LOOKUP(k string) *myElement {
	_, ok := DATA[k]
	if ok {
		n := DATA[k]
		return &n
	}
	return nil
}
func ADD(k string, n myElement) bool {
	if k == "" {
		return false
	}
	if LOOKUP(k) == nil {
		DATA[k] = n
		return true
	}
	return false
}
func DELETE(k string) bool {
	if LOOKUP(k) != nil {
		delete(DATA, k)
		return true
	}
	return false
}
func CHANGE(k string, n myElement) bool {
	DATA[k] = n
	return true
}

其他操作

func PRINT() {
	for k, v := range DATA {
		fmt.Printf("key: %s value: %v\n", k, v)
	}
}

项目入口

读取输入

最开始部分的scanner.Scan()会预读当前位置的下一位置,来判断是否读到头了. scanner.Text()会将最新读到的内容转换成string返回. strings.TrimsSpace()就是去掉首尾的的若干空格 strings.Fields()能把一串string按分割符' ',分割并返回[]string

该部分代码读取用户的输入。首先,for循环将保证程序一直等待用户的输入,接下来使用tokens切片保证至少有5个元素的输入,即使只有ADD命令需要5个参数。

func main(){
	scanner:=bufio.NewScanner(os.Stdin)
	for scanner.Scan(){
		text:=scanner.Text() // " 1 2 3"
		text=strings.TrimSpace(text)//"1 2 3"
		tokens:=strings.Fields(text)// "1","2","3"

		switch len(tokens){
		case 0:
			continue
		case 1:
			tokens=append(tokens, "")
			tokens=append(tokens, "")
			tokens=append(tokens, "")
			tokens=append(tokens, "")
		case 2:
			tokens=append(tokens, "")
			tokens=append(tokens, "")
			tokens=append(tokens, "")
		case 3:
			tokens=append(tokens, "")
			tokens=append(tokens, "")
		case 4:
			tokens=append(tokens, "")
		}
                ......

执行对应操作

                switch tokens[0] {
		case "PRINT":
			PRINT()
		case "STOP":
			return
		case "DELETE":
			if !DELETE(tokens[1]){
				fmt.Println("Delete operations failed")
			}
		case "ADD":
			n:=myElement{tokens[2],tokens[3],tokens[4]}
			if !ADD(tokens[1],n){
				fmt.Println("Add operation failed")
			}
		case "LOOKUP":
			n:=LOOKUP(tokens[1])
			if n!=nil{
				fmt.Printf("%+v\n",n)
			}
		case "CHANGE":
			n:=myElement{tokens[2],tokens[3],tokens[4]}
			if !CHANGE(tokens[1],n){
				fmt.Println("Update operation failed")
			}
		default:
			fmt.Println("Unknown command - please try again!")
		}
	}
}

运行结果

image.png