小规模商品搜索用 strings.contains 即可,但多条件、模糊匹配等需封装去空格转小写逻辑,用布尔标记累积筛选条件,参数需类型容错处理,排序须分层判断,高并发应引入索引或谓词函数。

小规模商品搜索(几百到几千条)直接用 strings.Contains + 内存遍历就能跑通,但一旦加了多字段、多条件、排序或模糊需求,硬写 if-else 就会失控。关键不是“能不能搜”,而是“加一个新筛选项要不要重写整个逻辑”。
用 strings.Contains 做基础关键词搜索时,大小写和空格怎么处理
用户输 “iphone”,你不能只匹配 “iPhone” 而漏掉 “IPHONE” 或 “ iPhone ”。标准库不提供开箱即用的“忽略首尾空格+忽略大小写”组合,得自己封装:
- 先用
strings.TrimSpace去掉输入两端空格,避免" iphone "匹配失败 - 再用
strings.ToLower统一转小写,对商品名、描述等字段也做同样转换后比对 - 别直接在循环里反复调
strings.ToLower(product.Name)——字段多、数据量大时会重复分配内存;建议提前建好nameLower字段缓存,或用strings.Contains(strings.ToLower(product.Name), keyword)这种一次性的写法
多个筛选条件(价格区间、分类 ID、是否上架)如何组合拼接
常见错误是把所有条件塞进一个 if 判断里,导致新增一个状态字段就得改十几行逻辑。更稳的做法是用布尔标记逐个累积:
- 初始化
match := true - 每个条件单独判断:
if priceMin > 0 && product.Price ,<code>if categoryID > 0 && product.CategoryID != categoryID { match = false } - 最后只保留
if match { results = append(results, product) } - 这样加新条件只需追加一段 if,不会干扰原有分支,也方便后期抽成独立函数(比如
filterByStock())
前端传来的筛选参数类型不一致(如 price_min 是 string)怎么办
HTTP 查询参数全是字符串,price_min=100 看似是数字,实际是 "100"。直接传给 strconv.Atoi 可能 panic,必须做容错:
- 用
strconv.ParseFloat(r.URL.Query().Get("price_min"), 64),并检查 error 是否为nil;非数字值(如空字符串、"abc")就跳过该条件,而不是报 500 - 布尔值同理:不要靠
r.URL.Query().Get("is_on_sale") == "true",而要用strings.EqualFold(val, "true") || val == "1"兼容常见前端传法 - Gin 框架下可用
c.Query("price_min")替代原始 query 获取,语义更清晰
搜索结果要按销量降序、价格升序排列,sort.Slice 怎么写才不出错
sort.Slice 的 Less 函数返回 true 表示“前面的应该排在前面”,这个方向容易反。销量降序 + 价格升序的复合排序必须严格分层判断:
sort.Slice(products, func(i, j int) bool {
a, b := products[i], products[j]
if a.Sales != b.Sales {
return a.Sales > b.Sales // 销量高的在前
}
return a.Price
- 千万不能写成
a.Sales > b.Sales && a.Price ——这会导致销量相等时整个表达式为 false,排序结果不可控 - 如果字段可能为 nil(比如用指针类型),先判空再比较,否则 panic
- 大数据量(>1w 条)时,这种内存排序会阻塞请求;真要撑住高并发,得提前在数据库加索引或引入倒排索引结构
真正卡住人的从来不是“怎么写出第一个搜索”,而是“当运营突然说要支持‘标题包含+详情页包含+品牌名精确匹配’三者任选其二”时,代码还能不能只改一行就上线。筛选逻辑越早抽象成可组合的谓词函数(predicate),后面就越省力。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











