Golang中Map已赋值却显示为nil的问题如何解决
Golang中Map已赋值却显示为nil的问题如何解决
Go 版本:1.12.2
错误信息:panic: assignment to entry in nil map
我知道仅声明 var myMap map[string]int 会导致向 nil 映射赋值的问题,必须使用 myMap := make(map[string]int)。但我似乎在一个已经赋值过的映射上遇到了同样的问题。以下是简化后的代码。请注意,我为了排查问题添加了许多多余的内容(尽管我已经尽量删除了很多):
for frm := range input {
go func() {
detMap := make(map[string][]image.Rectangle)
tmpRect := []image.Rectangle{image.Rectangle{image.Point{0, 0}, image.Point{1, 1}}}
detMap["init"] = tmpRect
tmpImg, _, _, _, detMap, sublError = imageFrames.Sublimate(frm)
rects := det.DetectMultiScale(tmpImg)
detMap[fname] = rects
frm.Detections = detMap
output <- frm
return
}()
}
我添加了 “tmpRect” 是为了确保 detMap 实际上不是 nil。ImageFrames.Sublimate() 如下:
func Sublimate(inFrm Frame) (gocv.Mat, string, []byte, map[int]image.Rectangle, map[string][]image.Rectangle, error) {
retMap := make(map[string][]image.Rectangle)
retMot := make(map[int]image.Rectangle)
retMap = inFrm.Detections
retMot = inFrm.MotionMap
retMat, err := gocv.NewMatFromBytes(inFrm.Wid, inFrm.Hei, inFrm.Type, inFrm.MatBytes)
return retMat, inFrm.UserName, inFrm.UserHash, retMot, retMap, err
}
即使我不预先创建映射,直接使用 tmpImg, _, _, _, detMap, sublError := imageFrames.Sublimate(frm),也会遇到同样的问题。
更多关于Golang中Map已赋值却显示为nil的问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
哪一行?
detMap[fname] = rects
更多关于Golang中Map已赋值却显示为nil的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这源于我为了弄清楚发生了什么而对源代码进行的反复折腾。我不断添加和删除内容,试图找出问题发生的位置。从未想过问题根本不在这个过程中。
这里的panic来自哪一行?这应该能指出是哪一行的map访问操作中map为nil。
func main() {
fmt.Println("hello world")
}
retMap = inFrm.Detections
这个值是 nil 吗?你在 Sublimate 函数中创建了 retMap,但随后用 inFrm.Detections 中的任何值覆盖了它,然后将其返回。
编辑: 哎呀。我漏看了你已经发现了。没关系!
问题已解决!
问题源于创建“Frame”类型。我创建它们的过程与从网络摄像头获取图像的过程完全不同。这些帧随后被编码并通过管道传输。当我最初创建Frame类型时,我编写了一个函数,用于在整个项目中需要创建新帧时生成新帧,但当时我并未在其中包含OpenCV检测结果的映射。
当我在项目中添加计算机视觉功能时,我没有更新创建空白帧的函数,而仅仅在结构体中添加了相应的字段。这意味着,此后创建的所有新帧在检测映射字段的位置上都会是一个nil值。
这个带有nil检测映射的帧会被编码并通过管道发送,从而在此过程中引发问题。感谢大家的帮助和建议。
尝试将 frm 的当前值传递给 goroutine。示例:
package main
import (
"fmt"
"time"
)
func main() {
input := []int{2, 4, 6, 8, 10}
for i := range input {
go func(x int) {
processValue(x)
}(input[i])
}
time.Sleep(10)
}
func processValue(value int) {
fmt.Println(value)
}
或者用变量 “i” 替换 “input[i]”。否则,你可能会遇到并发问题。
package main
import (
"fmt"
"time"
)
func main() {
input := []int{2, 4, 6, 8, 10}
for i := range input {
go func(x int) {
processValue(x)
}(i)
}
time.Sleep(10)
}
func processValue(value int) {
fmt.Println(value)
}
我尝试了那个方法,但最终还是遇到了同样的错误。我已经重写了函数,包含了来自 Sublimate() 的代码行,但我仍然遇到这个问题。我也完全移除了匿名函数,所以现在这只是一个带有输入通道和输出通道的串行循环。新的、未精简的版本如下:
func detect(input chan okoframe.Frame, output chan okoframe.Frame, classifierLocation string) {
for frm := range input {
//go func(frm okoframe.Frame) {
var tmpImg gocv.Mat
var sublError error
//tmpImg, _, _, _, detMap, sublError := okoframe.Sublimate(frm)
//StartSublimate--------------------------------------------------------------------------------------------
tmpImg, nmfbError := gocv.NewMatFromBytes(frm.Wid, frm.Hei, frm.Type, frm.MatBytes)
if nmfbError != nil {
fmt.Println("Sublimate fail:", nmfbError)
}
//END SUBLIMATE---------------------------------------------------------------------------------------
fname := filepath.Base(classifierLocation)
fmt.Println("Loading classifier from :", fname)
det := gocv.NewCascadeClassifier()
if !det.Load(fname) {
fmt.Errorf("Couldn't load classifier.")
os.Exit(1)
}
rects := det.DetectMultiScale(tmpImg)
//detMap[fname] = rects
frm.Detections[fname] = rects
//frm.Detections = detMap
if sublError != nil {
fmt.Println("Big error with sublimate stuff:", sublError)
frm.ErrList = append(frm.ErrList, sublError)
}
output <- frm
//return
//}(frm)
}
}
这真是太奇怪了。我确信这完全是我忽略的某个愚蠢的小问题,但是,唉。
问题出在 Sublimate 函数返回的 retMap 是 inFrm.Detections 的副本。当 inFrm.Detections 为 nil 时,retMap 也会是 nil。即使你在调用前初始化了 detMap,但函数返回时重新赋值了 detMap 变量,覆盖了之前初始化的映射。
以下是修复后的代码:
1. 修改 Sublimate 函数,避免返回 nil 映射:
func Sublimate(inFrm Frame) (gocv.Mat, string, []byte, map[int]image.Rectangle, map[string][]image.Rectangle, error) {
// 确保返回的映射不为 nil
retMap := inFrm.Detections
if retMap == nil {
retMap = make(map[string][]image.Rectangle)
}
retMot := inFrm.MotionMap
if retMot == nil {
retMot = make(map[int]image.Rectangle)
}
retMat, err := gocv.NewMatFromBytes(inFrm.Wid, inFrm.Hei, inFrm.Type, inFrm.MatBytes)
return retMat, inFrm.UserName, inFrm.UserHash, retMot, retMap, err
}
2. 或者,在主代码中检查返回的映射:
for frm := range input {
go func(frm Frame) {
tmpImg, _, _, _, detMap, sublError := imageFrames.Sublimate(frm)
if sublError != nil {
// 处理错误
return
}
// 检查 detMap 是否为 nil
if detMap == nil {
detMap = make(map[string][]image.Rectangle)
}
rects := det.DetectMultiScale(tmpImg)
detMap[fname] = rects
frm.Detections = detMap
output <- frm
}(frm)
}
3. 另一种方案是修改 Frame 结构体,确保 Detections 字段始终被初始化:
type Frame struct {
// 其他字段...
Detections map[string][]image.Rectangle
MotionMap map[int]image.Rectangle
}
// 在创建 Frame 时初始化映射
func NewFrame() Frame {
return Frame{
Detections: make(map[string][]image.Rectangle),
MotionMap: make(map[int]image.Rectangle),
}
}
第一种方案是最直接的修复,确保 Sublimate 函数永远不会返回 nil 映射。这样调用方就不需要额外检查。

