Go實現簡單的K-V儲存

hantmac發表於2019-01-27

Go實現簡單的K-V儲存

使用Go實現簡單的K-V儲存,包括基本的增刪改查功能。

本節程式碼將實現K-V儲存的四個基本功能:

  • 新增新元素
  • 基於key刪除已有的元素
  • 給定key查詢對應value
  • 修改key對應的value

我們將這四個功能命名為ADD,DELETE,LOOKUP,CHANGE,完成這四個基本功能,你將會對K-V儲存的實現有一個全面的瞭解。另外,當你輸入STOP時整個程式就會停止,輸入PRINT命令就會列印出當前K-V儲存的所有內容。

本節的keyValue.go將分為5個程式碼段解釋。

第一部分:

package main

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

type myElement struct {
   Name string
   SurName string
   Id string
}

var DATA = make(map[string]myElement)
複製程式碼

我們使用原生的Go map來實現K-V儲存,因為內建的資料結構往往執行效率更高。map變數被宣告為全域性變數,其k為string型別,v為myElement型別,myElement是自定義的結構體。

第二部分程式碼:

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
}
複製程式碼

這部分程式碼實現了命令列ADD和DELETE,使用者在執行ADD命令時,如果沒有攜帶足夠的引數,我們要保證該操作不會失敗,意味著myElement中對應的欄位為空字串。然而如果你要新增的key已經存在了,就會報錯(K-V儲存不允許重複key出現)而不是修改對應的值。

第三部分程式碼:

func LOOKUP(k string) *myElement  {
   _, ok := DATA[k]
   if ok {
      n := DATA[k]
      return &n
   } else {
      return nil
   }
}

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",k,v)
   }
}
複製程式碼

該程式碼段實現了LOOKUP與CHANGE功能,如果你要修改的key不儲存,程式會自動將其儲存。

PRINT命令能夠列印出目前所有K-V儲存的內容。

第四部分程式碼:

func main() {
   scanner := bufio.NewScanner(os.Stdin)
   for scanner.Scan() {
      text := scanner.Text()
      text = strings.TrimSpace(text)
      tokens := strings.Fields(text)

      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,"")
      
      }
複製程式碼

該部分程式碼讀取使用者的輸入。首先,for迴圈將保證程式一直等待使用者的輸入,接下來使用tokens切片保證至少有5個元素的輸入,即使只有ADD命令需要5個引數。如果使用者不想在使用ADD命令時出現空字串值,就需要這樣輸入:ADD aKey Field1 Field2 Field3。

最後一部分程式碼:

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!")

      }
   }
}
複製程式碼

這部分程式碼處理使用者的輸入。switch的使用使得程式的邏輯設計看上去十分清晰,能夠將程式設計師從冗餘的if...else中拯救出來。

執行keyValue.go得到如下輸出:

$ go run keyValue.go
UNKNOWN
Unknown command - please try again!

ADD 123 1 2 3
ADD 234 2 3 4
ADD 234
Add operation failed
ADD 345
PRINT
key: 123 value: {1 2 3}key: 234 value: {2 3 4}key: 345 value: {  }
CHANGE 345 3 4 5
PRINT
key: 345 value: {3 4 5}key: 123 value: {1 2 3}key: 234 value: {2 3 4}
DELETE 345
PRINT
key: 123 value: {1 2 3}key: 234 value: {2 3 4}
ADD 567 -5 -6 -7
PRINT
key: 123 value: {1 2 3}key: 234 value: {2 3 4}key: 567 value: {-5 -6 -7}
CHANGE 567
PRINT
key: 567 value: {  }key: 123 value: {1 2 3}key: 234 value: {2 3 4}  
STOP
複製程式碼

本文節選自Mastring_Go_ZH_CN

檢視並執行文中程式碼

戳我完整閱讀本書

戳我提出你的建議

相關文章