ฉันรู้ว่าฉันสามารถทำซ้ำแผนที่m
โดย
for k, v := range m { ... }
และมองหากุญแจ แต่มีวิธีที่มีประสิทธิภาพมากกว่าในการทดสอบการมีอยู่ของกุญแจในแผนที่หรือไม่?
ฉันรู้ว่าฉันสามารถทำซ้ำแผนที่m
โดย
for k, v := range m { ... }
และมองหากุญแจ แต่มีวิธีที่มีประสิทธิภาพมากกว่าในการทดสอบการมีอยู่ของกุญแจในแผนที่หรือไม่?
คำตอบ:
คำตอบหนึ่งบรรทัด:
if val, ok := dict["foo"]; ok {
//do something here
}
if
คำสั่งใน Go สามารถรวมทั้งเงื่อนไขและคำสั่งการเริ่มต้น ตัวอย่างข้างต้นใช้ทั้ง:
เริ่มต้นตัวแปรสองตัว - val
จะได้รับค่า "foo" จากแผนที่หรือ "ค่าศูนย์" (ในกรณีนี้คือสตริงว่าง) และok
จะได้รับค่าบูลที่จะถูกตั้งค่าtrue
หาก "foo" แสดงอยู่ในแผนที่
ประเมินok
ซึ่งจะเป็นtrue
ถ้า "foo" อยู่ในแผนที่
หาก "foo" มีอยู่จริงในแผนที่เนื้อความของif
คำสั่งจะถูกดำเนินการและval
จะอยู่ในขอบเขตนั้น
var val string = ""
จะยังคงเหมือนเดิมval, ok :=
สร้างตัวแปรท้องถิ่นใหม่ที่มีชื่อเดียวกับที่มองเห็นได้ในบล็อกนั้น
if key in dict
ไวยากรณ์สับสนดังกล่าวเมื่อเทียบกับของงูหลาม
นอกเหนือจากการที่ไปเขียนโปรแกรมภาษาข้อมูลจำเพาะคุณควรอ่านที่มีประสิทธิภาพไป ในส่วนบนแผนที่พวกเขาพูดในสิ่งอื่น ๆ :
ความพยายามในการดึงค่าแผนที่ด้วยรหัสที่ไม่มีอยู่ในแผนที่จะคืนค่าศูนย์สำหรับประเภทของรายการในแผนที่ ตัวอย่างเช่นหากแผนที่มีจำนวนเต็มการค้นหาคีย์ที่ไม่มีอยู่จะส่งคืน 0 ชุดสามารถดำเนินการเป็นแผนที่ที่มีค่าประเภทบูล ตั้งค่ารายการแผนที่เป็นจริงเพื่อใส่ค่าในชุดแล้วทดสอบโดยการทำดัชนีอย่างง่าย
attended := map[string]bool{ "Ann": true, "Joe": true, ... } if attended[person] { // will be false if person is not in the map fmt.Println(person, "was at the meeting") }
บางครั้งคุณต้องแยกความแตกต่างของรายการที่หายไปจากค่าศูนย์ มีรายการสำหรับ "UTC" หรือว่าเป็น 0 เพราะมันไม่ได้อยู่ในแผนที่เลยเหรอ? คุณสามารถแยกแยะด้วยรูปแบบของการมอบหมายหลาย
var seconds int var ok bool seconds, ok = timeZone[tz]
ด้วยเหตุผลที่ชัดเจนสิ่งนี้เรียกว่าสำนวน“ comma ok” ในตัวอย่างนี้ถ้ามี tz วินาทีจะถูกตั้งค่าอย่างเหมาะสมและตกลงจะเป็นจริง ถ้าไม่ใช่วินาทีจะถูกตั้งค่าเป็นศูนย์และตกลงจะเป็นเท็จ นี่คือฟังก์ชันที่รวมเข้ากับรายงานข้อผิดพลาดที่ดี:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
ในการทดสอบการมีอยู่ในแผนที่โดยไม่ต้องกังวลเกี่ยวกับค่าจริงคุณสามารถใช้ตัวระบุที่ว่างเปล่า (_) แทนตัวแปรปกติสำหรับค่า
_, present := timeZone[tz]
ค้นหาในรายชื่ออีเมล go-nutsและพบวิธีแก้ไขปัญหาที่โพสต์โดย Peter Froehlich เมื่อวันที่ 11/15/2009
package main
import "fmt"
func main() {
dict := map[string]int {"foo" : 1, "bar" : 2}
value, ok := dict["baz"]
if ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
}
หรือมากกว่าดาน
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
หมายเหตุการใช้รูปแบบของif
คำสั่งนี้value
และok
ตัวแปรจะมองเห็นได้เฉพาะภายในif
เงื่อนไข
_, ok := dict["baz"]; ok
หากคุณจริงๆมีความสนใจเพียงในไม่ว่าจะเป็นกุญแจสำคัญในการมีอยู่หรือไม่และไม่สนใจเกี่ยวกับค่าที่คุณสามารถใช้ _
ส่วนพ่นค่าออกไปแทนการสร้างตัวแปรชั่วคราว
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
นี่คือตัวอย่างที่ไปสนามเด็กเล่น
ตามส่วนแผนที่ของการใช้งานที่มีประสิทธิภาพ :
ความพยายามในการดึงค่าแผนที่ด้วยรหัสที่ไม่มีอยู่ในแผนที่จะคืนค่าศูนย์สำหรับประเภทของรายการในแผนที่ ตัวอย่างเช่นหากแผนที่มีจำนวนเต็มการค้นหาคีย์ที่ไม่มีอยู่จะส่งคืนค่า 0
บางครั้งคุณต้องแยกความแตกต่างของรายการที่หายไปจากค่าศูนย์ มีรายการสำหรับ "UTC" หรือว่าเป็นสตริงว่างเพราะมันไม่ได้อยู่ในแผนที่เลย? คุณสามารถแยกแยะด้วยรูปแบบของการมอบหมายหลาย
var seconds int var ok bool seconds, ok = timeZone[tz]
ด้วยเหตุผลที่ชัดเจนสิ่งนี้เรียกว่าสำนวน“ comma ok” ในตัวอย่างนี้ถ้ามี tz วินาทีจะถูกตั้งค่าอย่างเหมาะสมและตกลงจะเป็นจริง ถ้าไม่ใช่วินาทีจะถูกตั้งค่าเป็นศูนย์และตกลงจะเป็นเท็จ นี่คือฟังก์ชันที่รวมเข้ากับรายงานข้อผิดพลาดที่ดี:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
ในการทดสอบการมีอยู่ในแผนที่โดยไม่ต้องกังวลเกี่ยวกับค่าจริงคุณสามารถใช้ตัวระบุที่ว่างเปล่า (_) แทนตัวแปรปกติสำหรับค่า
_, present := timeZone[tz]
ตามที่ระบุไว้โดยคำตอบอื่น ๆ การแก้ปัญหาทั่วไปคือการใช้การแสดงออกของดัชนีในการกำหนดรูปแบบพิเศษ:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
นี่เป็นสิ่งที่ดีและสะอาด มันมีข้อ จำกัด บางอย่าง แต่ต้องเป็นแบบฟอร์มพิเศษ การแสดงออกทางด้านขวามือจะต้องเป็นการแสดงออกของดัชนีแผนที่เท่านั้นและรายการการแสดงออกทางซ้ายมือจะต้องมีตัวถูกดำเนินการ 2 ตัวโดยแรกคือประเภทของค่าที่กำหนดได้และที่สองที่เป็นbool
ค่าที่สามารถกำหนดได้ ค่าแรกของผลลัพธ์ของฟอร์มพิเศษนี้จะเป็นค่าที่เชื่อมโยงกับคีย์และค่าที่สองจะบอกได้ว่ามีรายการในแผนที่ที่มีคีย์ที่กำหนดหรือไม่ (ถ้ามีคีย์อยู่ในแผนที่) รายการนิพจน์ด้านซ้ายอาจมีตัวระบุที่ว่างเปล่าหากไม่ต้องการผลลัพธ์อย่างใดอย่างหนึ่ง
สิ่งสำคัญคือต้องรู้ว่าหากค่าแผนที่ที่จัดทำดัชนีเป็นnil
หรือไม่มีคีย์นิพจน์ดัชนีจะประเมินค่าเป็นศูนย์ของประเภทค่าของแผนที่ ตัวอย่างเช่น:
m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0
fmt.Printf("%q %f", s, f) // Prints: "" 0.000000
ลองใช้ในสนามเด็กเล่นไป
ดังนั้นหากเรารู้ว่าเราไม่ได้ใช้ค่าศูนย์ในแผนที่ของเราเราสามารถใช้ประโยชน์จากสิ่งนี้
ตัวอย่างเช่นหากประเภทค่าคือstring
และเรารู้ว่าเราไม่เคยเก็บรายการไว้ในแผนที่โดยที่ค่าเป็นสตริงว่าง (ค่าศูนย์สำหรับstring
ประเภท) เราสามารถทดสอบได้ว่าคีย์อยู่ในแผนที่หรือไม่โดยการเปรียบเทียบค่าที่ไม่พิเศษ รูปแบบของการแสดงออกของดัชนี (ผลลัพธ์ของ) เป็นศูนย์:
m := map[int]string{
0: "zero",
1: "one",
}
fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t",
m[0] != "", m[1] != "", m[2] != "")
เอาท์พุท (ลองไปที่สนามเด็กเล่น Go ):
Key 0 exists: true
Key 1 exists: true
Key 2 exists: false
ในทางปฏิบัติมีหลายกรณีที่เราไม่เก็บค่า zero-value ไว้ในแผนที่ดังนั้นจึงสามารถใช้งานได้บ่อยครั้ง ตัวอย่างเช่นอินเทอร์เฟซและประเภทฟังก์ชั่นมีค่าเป็นศูนย์nil
ซึ่งเรามักจะไม่เก็บไว้ในแผนที่ nil
ดังนั้นการทดสอบถ้าคีย์อยู่ในแผนที่สามารถทำได้โดยการเปรียบเทียบกับ
การใช้ "เทคนิค" นี้มีข้อดีอีกอย่างเช่นกัน: คุณสามารถตรวจสอบการมีอยู่ของปุ่มหลายปุ่มได้ในแบบกะทัดรัด (คุณไม่สามารถทำได้ด้วยแบบฟอร์ม "comma ok" พิเศษ) เพิ่มเติมเกี่ยวกับสิ่งนี้: ตรวจสอบว่ามีรหัสอยู่ในหลาย ๆ แผนที่ในสภาพเดียวหรือไม่
ได้รับค่าเป็นศูนย์ของประเภทค่าเมื่อการจัดทำดัชนีด้วยกุญแจไม่ใช่ที่มีอยู่นอกจากนี้ยังช่วยให้เราสามารถใช้แผนที่ที่มีbool
ค่าสะดวกเป็นชุด ตัวอย่างเช่น:
set := map[string]bool{
"one": true,
"two": true,
}
fmt.Println("Contains 'one':", set["one"])
if set["two"] {
fmt.Println("'two' is in the set")
}
if !set["three"] {
fmt.Println("'three' is not in the set")
}
มันออกมา (ลองบนสนามเด็กเล่น Go ):
Contains 'one': true
'two' is in the set
'three' is not in the set
ดูที่เกี่ยวข้อง: ฉันจะสร้างอาร์เรย์ที่มีสตริงที่ไม่ซ้ำได้อย่างไร
T
ในvar v, ok T = a[x]
? ไม่ok
ต้องเป็นคนโง่
map[bool]bool
และT
เป็นbool
แต่ก็ยังทำงานหากแผนที่เป็นชนิดmap[interface{}]bool
และT
เป็นinterface{}
; ยิ่งไปกว่านั้นมันยังทำงานร่วมกับประเภทที่กำหนดเองต้องbool
เป็นชนิดพื้นฐานดูทั้งหมดบนไปสนามเด็กเล่น ดังนั้นเนื่องจากรูปแบบนั้นใช้ได้กับการทดแทนหลายประเภทT
นั่นจึงเป็นเหตุผลที่T
ใช้งานทั่วไป ประเภทของok
สามารถเป็นอะไรก็ได้ที่สามารถกำหนดชนิดuntypedbool
ได้
วิธีที่ดีกว่าที่นี่
if _, ok := dict["foo"]; ok {
//do something here
}
var d map[string]string
value, ok := d["key"]
if ok {
fmt.Println("Key Present ", value)
} else {
fmt.Println(" Key Not Present ")
}
var empty struct{}
var ok bool
var m map[string]struct{}
m = make(map[string]struct{})
m["somestring"] = empty
_, ok = m["somestring"]
fmt.Println("somestring exists?", ok)
_, ok = m["not"]
fmt.Println("not exists?", ok)
ถ้างั้นไปเรียกใช้ maps.go มีอยู่ไหม จริงไม่ได้อยู่หรือ เท็จ
_, ok = m["somestring"]
ควรเป็น=_, ok := m["somestring"]
การกำหนดค่าสองค่าสามารถนำมาใช้เพื่อจุดประสงค์นี้ โปรดตรวจสอบโปรแกรมตัวอย่างของฉันด้านล่าง
package main
import (
"fmt"
)
func main() {
//creating a map with 3 key-value pairs
sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
//A two value assignment can be used to check existence of a key.
value, isKeyPresent := sampleMap["key2"]
//isKeyPresent will be true if key present in sampleMap
if isKeyPresent {
//key exist
fmt.Println("key present, value = ", value)
} else {
//key does not exist
fmt.Println("key does not exist")
}
}