登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

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 和具体错误,能够分辨容量、分块及具体实现的问题,避免只保留一句“输入非法”。

参考:Transformer 接口、Bytes 文档。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>