Golang查询中无记录返回的陷阱与解决方案
Golang查询中无记录返回的陷阱与解决方案 是否有办法捕获空接口?
我从Postgresql获取数据并填充一个列表。如果列表为空,我希望重定向到另一个页面。以下是我的尝试(未成功):
list := Get(query)
switch list {
case nil:
returns []
fmt.Println("no result")
default:
returns [map[post_id:1 post_subject:Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...] map[post_id:2 post_subject:Vestibulum ante ipsum primis in faucibus orci luctus et ultrices]]
fmt.Println("show result")
}
更多关于Golang查询中无记录返回的陷阱与解决方案的实战教程也可以访问 https://www.itying.com/category-94-b0.html
嗨,@Sibert,哪里出问题了?是构建时还是使用时出错?错误信息是什么?
更多关于Golang查询中无记录返回的陷阱与解决方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
skillian:
哪里出了问题?
无论是否为空,结果都完全一样。没有错误。
[ ] 给出 OK
[map[post_id:1] 给出 OK
nil 切片与空切片并不相同;切片可能已经初始化但没有任何元素。与其使用:
switch list {
case nil:
// ...
我建议:
switch {
case len(list) == 0:
// 没有结果。
default:
// 至少有一个结果
}
skillian:
你能把这个完整的例子放到 Go Playground 和/或某个可公开访问的源代码控制仓库中吗?
目的是在用户搜索时呈现“无数据”,并且没有记录可显示。
http://94.237.92.101:3030/mytopics
这不是完整的例子,但包含了核心部分。
我需要在某个地方检查列表是否不包含数据。据我所知,errNoRows 不起作用。
如果
Get(query)返回空接口
这个方向是正确的还是死胡同?

Go Playground - The Go Programming Language
package main
import (
"fmt"
)
func main() {
list := map[string]string{"id": "kjh"}
listempty := map[string]string{"id": ""}
result1 := check(len(list["id"]))
result2 := check(len(listempty["id"]))
fmt.Println(result1)
fmt.Println(result2)
}
func check(ok int) string {
switch ok {
case 0:
return ("empty")
default:
return ("OK")
}
}
如果 Get(query) 返回空接口,并且在无结果时不返回 nil,我不确定正确的处理方式。我会考虑重构那个 Get 函数以返回更合适的类型,但在此期间,你可以尝试:
import "reflect"
func isEmpty(v interface{}) bool {
if v == nil {
return true
}
switch v := v.(type) {
case []interface{}: // 也许在回退到反射之前先测试一些其他类型
return len(v) == 0
default:
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
return rv.Len() == 0
}
return false
}
}
list := Get(query)
switch {
case isEmpty(list):
// ...
default:
// else
}
skillian:
你最新的例子与我最初的设想有很大不同。
我在最初的问题中写道:
“我从Postgresql获取数据并填充一个列表。如果列表为空,我想重定向到另一个页面。” 目的是告诉用户没有获取到数据。
我能想到的有两种选择:
- 在查询过程中检查数据库,看结果是否为空。
- 在查询结果返回后检查结果。
在其他一些语言中,你可以用一种简单的方式同时完成这两件事,但Go语言让这变得困难。例如,选项#1和#2都可以像 If list.$linecount=0… 这样实现。
由于Go语言是另一种“野兽”,而我完全是个新手,我很难理解为什么检查查询结果是否为空不能更简单一些。
比如,当使用 db.QueryRow 时,Scan 会返回 ErrNoRows,但不知为何,对于 db.Query(…) 生成的列表却不这样。
@Sibert 那是在检查映射中是否有任何键值对,但我推测你在第一篇帖子中打印的 list 表示形式:
Sibert:
returns [map[post_id:1 post_subject:Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...] map[post_id:2 post_subject:Vestibulum ante ipsum primis in faucibus orci luctus et ultrices]]
看起来是一个映射切片,所以检查单个映射的长度不会告诉你是否存在任何映射。
我试图根据伪代码和 panic 消息对你想要做的事情做出合理的猜测,但你最新的例子与我最初的假设有很大不同。如果你试图检查实际映射的长度,你最新的 Go Playground 示例会起作用,但如果你仍在寻找其他东西,你能把完整的例子放到 Go playground 和/或某个可公开访问的源代码控制仓库中吗?
在Golang中处理数据库查询无记录的情况,关键在于正确区分不同类型的"空值"。以下是几种常见的解决方案:
1. 检查切片长度(推荐)
list := Get(query)
if len(list) == 0 {
// 重定向到其他页面
fmt.Println("no result")
// return redirectToOtherPage()
} else {
fmt.Println("show result")
// 处理数据
for _, item := range list {
fmt.Printf("Post ID: %v\n", item["post_id"])
}
}
2. 使用类型断言检查nil
如果你的Get()函数可能返回nil切片:
list := Get(query)
if list == nil {
fmt.Println("nil slice - no result")
} else if len(list) == 0 {
fmt.Println("empty slice - no result")
} else {
fmt.Println("show result")
}
3. 改进Get函数返回错误
更健壮的做法是让Get()函数返回错误:
func Get(query string) ([]map[string]interface{}, error) {
rows, err := db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
var results []map[string]interface{}
for rows.Next() {
// 解析行数据到map
result := make(map[string]interface{})
// ... 填充数据
results = append(results, result)
}
if err = rows.Err(); err != nil {
return nil, err
}
return results, nil
}
// 使用方式
list, err := Get(query)
if err != nil {
// 处理数据库错误
log.Printf("Query error: %v", err)
return
}
if len(list) == 0 {
fmt.Println("no result")
// 重定向逻辑
} else {
fmt.Println("show result")
}
4. 使用结构体代替map(类型安全)
type Post struct {
ID int `db:"post_id"`
Subject string `db:"post_subject"`
}
func GetPosts(query string) ([]Post, error) {
var posts []Post
err := db.Select(&posts, query)
if err != nil {
return nil, err
}
return posts, nil
}
// 使用方式
posts, err := GetPosts(query)
if err != nil {
// 处理错误
}
if len(posts) == 0 {
fmt.Println("no posts found")
// 重定向
} else {
fmt.Printf("Found %d posts\n", len(posts))
for _, post := range posts {
fmt.Printf("ID: %d, Subject: %s\n", post.ID, post.Subject)
}
}
5. 针对你的switch语句修正
如果你想使用switch语句,可以这样写:
list := Get(query)
switch {
case list == nil:
fmt.Println("nil - no result")
case len(list) == 0:
fmt.Println("empty - no result")
// http.Redirect(w, r, "/other-page", http.StatusFound)
default:
fmt.Println("show result")
fmt.Printf("Results: %v\n", list)
}
关键点:
- 空切片
[]和nil切片在长度上都是0,但len()函数对两者都适用 - 使用
len(list) == 0可以同时处理nil切片和空切片的情况 - 对于数据库操作,建议始终返回错误以便正确处理异常情况

