Go 中使用 binary.Varint 解析单字节时结果减半的原因与解决方案
技术百科
花韻仙語
发布时间:2026-01-12
浏览: 次 `binary.varint` 专为有符号整数的变长编码设计,会将输入按 zigzag 编码规则解码(右移1位 + 符号位判断),导致 `byte(18)` 被误解析为 `9`;应改用 `binary.uvarint` 处理无符号字节序列。
在 Go 的 encoding/binary 包中,Varint 和 Uvarint 是两个关键但语义迥异的函数:
- binary.Uvarint(buf []byte) 用于解码 无符号变长整数(如 uint64),直接按 Base128 规则累加有效位,适用于 byte(即 uint8)、uint16、uint32 等原始无符号值;
- binary.Varint(buf []byte) 则专为 有符号整数的 ZigZag 编码 设计——它先调用 Uvarint 获取原始无符号值,再通过 x = (ux >> 1) ^ -(ux & 1) 进行 ZigZag 反变换,以支持负数高效编码(常用于 Protocol Buffers)。
你示例中的 by
te(18) 二进制为 00010010(8 位),传入 Varint 后流程如下:
- 内部调用 Uvarint(array) 得到 ux = 18;
- 执行 x = int64(ux >> 1) → 18 >> 1 = 9(即 00001001);
- 检查 ux & 1 == 0(18 & 1 = 0),不满足 ux&1 != 0 条件,跳过取反;
- 最终返回 x = 9 —— 这正是输出 value: 9 的根本原因。
✅ 正确做法是:对无符号字节序列(如 []byte{18})始终使用 Uvarint:
package main
import (
"fmt"
"encoding/binary"
)
func main() {
var myByte byte = 18
array := []byte{myByte}
// ❌ 错误:Varint 期望 ZigZag 编码的有符号值
val, n := binary.Varint(array)
fmt.Printf("Varint -> value: %d, num bytes: %d\n", val, n) // 输出: 9, 1
// ✅ 正确:Uvarint 直接解码无符号变长整数
uval, un := binary.Uvarint(array)
fmt.Printf("Uvarint -> value: %d, num bytes: %d\n", uval, un) // 输出: 18, 1
}⚠️ 注意事项:
- Varint/Uvarint 均要求输入字节切片符合 LEB128(Little-Endian Base128)格式:每个字节低 7 位存数据,最高位(bit 7)为 continuation bit(1 表示后续还有字节,0 表示结束)。单字节 []byte{18} 是合法的 LEB128 编码(18
- 若需编码 int64 类型的有符号值并保证跨语言兼容(如与 Protobuf 交互),才应先用 binary.PutVarint 编码,再用 Varint 解码;普通无符号数值场景请坚持 Uvarint;
- Varint 返回 int64,Uvarint 返回 uint64,注意类型匹配,避免隐式转换引发意外截断或符号扩展。
总结:byte 是 uint8 的别名,天然无符号;选择解码函数的核心原则是——编码方式决定解码方式。用 Uvarint 解 uint,用 Varint 解经 ZigZag 编码的 int,二者不可混用。
# ai
# 则是
# 适用于
# 跳过
# 专为
# 会将
# 先用
# 再用
# go
# 隐式转换
# int
# 编码
# 字节
# 切片
# 根本原因
# Array
# 变长
# ux
# 不满足
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何在 Django 中安全修改用户密码而不使会话
- LINUX的SELinux是什么_详解LINUX强
- c++怎么使用类型萃取type_traits_c+
- Windows系统时间服务错误_W32Time服务
- 如何使用Golang构建简易投票统计功能_Gola
- Python模块的__name__属性如何由导入方
- Win11怎么制作U盘启动盘_Win11原版系统安
- Win10如何更改任务栏高度_Windows10解
- Win11怎么关闭自动修复_跳过Win11开机自动
- Win11怎么关闭键盘按键音_Win11禁用打字声
- Python数据挖掘核心算法实践_聚类分类与特征工
- Win11怎么更改任务栏颜色_Windows11个
- Win11怎么开启空间音效_Windows11耳机
- Win11怎么关闭触摸键盘图标_Windows11
- 如何优化Golang程序CPU性能_Golang
- VSC怎么快速定位PHP错误行_错误追踪设置法【方
- Win11怎样安装钉钉客户端_Win11安装钉钉教
- Win11怎么设置鼠标宏_Win11鼠标按键自定义
- 如何在Golang中处理通道发送接收错误_防止阻塞
- Win11蓝牙开关不见了怎么办_Win11蓝牙驱动
- php转exe用什么工具打包快_高效打包软件推荐【
- Windows 11无法安全删除U盘提示设备正在使
- 如何使用Golang开发简单的聊天室消息存储_Go
- 如何使用Golang实现基本类型比较_Golang
- 如何使用 Selenium 正确获取篮球参考网站球
- Python对象生命周期管理_创建销毁解析【教程】
- windows系统如何安装cab更新补丁_wind
- Win11怎么关闭任务栏小图标_Windows11
- 如何在 Go 中创建包含映射(map)的切片(sl
- Win11关机快捷键是什么_Win11快速关机方法
- php后缀怎么变mp4能播放_让php伪装mp4正
- 如何优化Golang Web性能_Golang H
- 短链接怎么用php递归还原_多层加密链接的处理法【
- Windows10系统更新错误0x80070002
- Windows 11如何查看系统激活密钥_Wind
- Win11怎么关闭触摸屏_禁用Win11笔记本触摸
- PythonDocker高级项目部署教程_多容器管
- Windows 11如何开启文件夹加密(EFS)_
- Win11怎么设置组合键快捷方式_Windows1
- Windows7如何安装系统镜像_Windows7
- mac怎么安装adb_MAC配置Android A
- Win11怎么用设置清理回收站_Win11设置清理
- 如何在 Go 中调用动态链接库(.so)中的函数
- php怎么下载安装后测试是否成功_简单脚本验证方法
- Win11如何设置开机自动联网 Win11宽带连接
- Win10电脑怎么设置网络名称_Windows10
- Win11怎样安装网易云音乐_Win11安装网易云
- Win11怎样安装企业微信_Win11安装企业微信
- Windows10蓝屏SYSTEM_SERVICE
- Python与MongoDB NoSQL开发实战_

QQ客服