Go x/text/transform ErrShortDst 为什么不代表输入非法
来源:17golang原创
时间:2026-10-27 06:30:01 312浏览 收藏
ErrShortDst 表示本次目标切片的空间不足,不能用来判断输入非法。它属于输出容量信号。输入是否合法,要看具体变换器的错误约定及应用自己的校验规则。正确处理的关键是先接收已经产生的输出、推进输入位置,再继续同一个变换器。
官方文档:https://pkg.go.dev/golang.org/x/text/transform
区分容量信号和输入合法性
Transform 返回 nDst、nSrc 和 err。前两个字段分别表示写入目标的字节数和消耗源数据的字节数;即使 err 非空,它们也可能包含有效进度。忽略这些计数,可能丢掉结果或者重复提交已处理输入。
| 返回信号 | 含义 | 处理重点 |
|---|---|---|
| ErrShortDst | 目标空间不足 | 保留输出并提供空间 |
| ErrShortSrc | 当前源数据不足 | 结合分块和结束标志处理 |
| 其他错误 | 由具体实现定义 | 按实现文档处理 |
如果源数据和输出空间同时不足,接口允许返回其中任一短缓冲区错误。因此,ErrShortDst 也不能证明输入没有其他问题。它只表达当前调用的一项受限条件。

用普通输入说明短目标错误
使用只复制字节的 transform.Nop,把普通 ASCII 输入交给较小目标区,就足以说明容量不足与非法输入是两回事。下面片段放在已导入 transform 的函数中;它用于解释接口,没有附带实测输出。
// 输入有两个字节,而目标只开放一个字节。
src := []byte("AB")
dst := make([]byte, 1)
nDst, nSrc, err := transform.Nop.Transform(dst, src, true)
// 使用输出和消耗计数后再解释 err,不能只判断错误字符串。
_, _, _ = nDst, nSrc, err
Nop 不承担 UTF-8 合法性检查。换成其他字符变换器,也应查清其替换、拒绝和错误报告策略。输入字节数与输出字节数没有通用的一比一保证,按 len(src) 分配 dst 不一定足够。
保留返回进度并连续转换
下面完整函数处理已经读齐的一份数据。atEOF=true 表示没有后续源数据,不意味着所有输出必须一次放完。每次调用都先记录输出和消耗量,再处理返回错误。
package example
import (
"fmt"
"golang.org/x/text/transform"
)
// ConvertAll 转换一份完整输入,错误时同时返回已产生的部分结果。
func ConvertAll(t transform.Transformer, input []byte) ([]byte, error) {
const maxChunk = 65536 // 应用选择的单次缓冲区上限,不是库限制。
t.Reset() // 独立任务开始时重置,循环中保持同一状态。
dst := make([]byte, 8)
src := input
var result []byte
for {
nDst, nSrc, err := t.Transform(dst, src, true)
result = append(result, dst[:nDst]...) // 先保留输出,再判断错误。
src = src[nSrc:] // 下次只提交尚未消耗的输入。
switch err {
case nil:
return result, nil
case transform.ErrShortDst:
if nDst == 0 && nSrc == 0 {
if len(dst) == maxChunk {
return result, fmt.Errorf("输出缓冲区达到上限且没有进展")
}
dst = make([]byte, len(dst)*2) // 零进展时扩大空间,避免空转。
}
// 有进展即可复用工作区;不 Reset,也不丢失内部待输出数据。
default:
return result, fmt.Errorf("已消耗 %d 字节: %w", len(input)-len(src), err)
}
}
}
当调用产生进展时,可以复用同一工作区接收下一段输出。若 nDst 和 nSrc 同时为零,只用相同缓冲区原样重试可能持续失败,因此示例增大工作区并设置上限。64 KiB 是示例应用策略,需按实际变换器调整;函数会把完整结果累积到内存,大数据场景还应设置总输出限制或采用流式写入。
不能仅凭 nSrc 等于当前输入长度结束任务:变换器可能还有内部待输出数据。源数据耗尽后仍可用空 src 继续承接输出,直到成功或得到其他应处理的错误。循环中 Reset 会清除状态,不能把它当作处理 ErrShortDst 的修复动作。遇到其他错误时,调用者应明确处理部分结果,不能将它默认为完整成功。

检查切片长度和接口选择
Transform 可写范围由 len(dst) 决定。make([]byte, 0, 1024) 的容量虽然是 1024,长度仍为零,直接传入并没有开放这部分空间。使用非零长度缓冲区,或者在明确用途后重新切片,才能让本次调用写入。
如果只是转换一份完整数据,可以使用 transform.Bytes 减少手写循环;它仍返回结果、消耗计数和错误。该函数会 Reset 变换器,因而不能随意插入正在进行的手动连续调用中。读取型任务也可考虑 transform.NewReader。手写循环适合需要明确掌握输出分段、工作区大小和部分结果策略的场景。
常见疑问
把 atEOF 改成 false 能解决吗?不能。它表达是否还有源数据,不能代替容量管理。实际分块场景还需要保留未消耗输入,并在真正结束时正确设置标志。
每次都要扩大缓冲区吗?不必。有进展时先排空输出并复用即可;零进展时调整空间策略,同时限制资源增长。
err 为 nil 是否就代表字符合法?不保证。完成变换和满足业务输入规范是两个判断。比如复制操作成功本身没有提供 UTF-8 检查。
排查时一起记录 len(dst)、nDst、nSrc、atEOF 和具体错误,能够分辨容量、分块及具体实现的问题,避免只保留一句“输入非法”。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
365 收藏
-
106 收藏
-
235 收藏
-
332 收藏
-
110 收藏
-
135 收藏
-
206 收藏
-
374 收藏
-
259 收藏
-
460 收藏
-
199 收藏
-
240 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习