<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>golang on cubatic's blog</title><link>https://blog.121306.xyz/tags/golang/</link><description>Recent content in golang on cubatic's blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 03 Nov 2025 15:33:10 +0800</lastBuildDate><atom:link href="https://blog.121306.xyz/tags/golang/index.xml" rel="self" type="application/rss+xml"/><item><title>Map_noswiss</title><link>https://blog.121306.xyz/posts/golang/map_noswiss/</link><pubDate>Mon, 03 Nov 2025 15:33:10 +0800</pubDate><guid>https://blog.121306.xyz/posts/golang/map_noswiss/</guid><description>以下代码为 golang 1.25.3
map_noswiss 常量 const ( // 每个 bucket 能够容纳的最大 key/val 的数量 bucketCntBits = abi.OldMapBucketCountBits // 当桶的平均装载量（load factor）超过 13/16 = 0.8125 时，会触发 map 扩容。 // 因为 bucketCnt 至少是 8，所以在对齐规则下性能是合理的。 // 这里用两个整数（分子 / 分母）来避免使用浮点数计算。 loadFactorDen = 2 loadFactorNum = loadFactorDen * abi.OldMapBucketCount * 13 / 16 // map 桶（bmap）结构中数据区（keys、values）相对于结构体起始地址的偏移量。 // 即 bmap 头部之后，键值对数据的起始位置。 // 为保证对齐，在某些架构（如 amd64p32）上，即使指针是 32 位，也要使用 64 位对齐。 dataOffset = unsafe.Offsetof(struct { b bmap v int64 }{}.v) emptyRest = 0 // 这个槽为空，并且后面不会再有非空项（用于快速扫描结束） emptyOne = 1 // 这个槽为空，但后面可能还有数据 evacuatedX = 2 // 此键值对已经迁移到新表（新表前一半） evacuatedY = 3 // 此键值对已迁移到新表（新表后一半） evacuatedEmpty = 4 // 桶已迁移完成，此槽为空 minTopHash = 5 // 正常已填充槽的最小 tophash 值 // flags iterator = 1 // 有迭代器正在使用当前 buckets oldIterator = 2 // 有迭代器正在使用旧的 old buckets（扩容时） hashWriting = 4 // 有 goroutine 正在写 map（防止并发写入） sameSizeGrow = 8 // 当前 map 扩容时，新旧 map 大小相同（即仅搬迁，不扩容） // 这是迭代器检查时的特殊哨兵值（bucket ID）， // 用于标识“不需要检查”的情况。 // 1&amp;lt;&amp;lt;(8*goarch.</description></item><item><title>Go Channel</title><link>https://blog.121306.xyz/posts/golang/chan/</link><pubDate>Wed, 09 Jul 2025 09:10:33 +0800</pubDate><guid>https://blog.121306.xyz/posts/golang/chan/</guid><description>以下代码为 golang 1.24.5
chan chan 底层 结构 const ( maxAlign = 8 // 最大对齐字节数（通常与架构相关） hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&amp;amp;(maxAlign-1)) // hchan 结构体的大小（含对齐填充） debugChan = false // 调试标志，是否开启 channel 调试 ) // Go 语言运行时中 channel 的底层结构 type hchan struct { qcount uint // 队列中当前的元素数量 dataqsiz uint // 环形缓冲区的大小（也就是 buf 中元素的总数） buf unsafe.Pointer // 指向实际数据缓冲区（数组，元素个数为 dataqsiz） elemsize uint16 // 每个元素的大小（字节） synctest bool // 是否用于 sync 包的测试中（true 表示在 synctest 模式中创建） closed uint32 // 标志位，表示 channel 是否已关闭 timer *timer // 用于超时操作的定时器指针（如 select 的超时） elemtype *_type // 指向元素类型的类型描述符 sendx uint // 当前发送的索引（用于环形缓冲区） recvx uint // 当前接收的索引（用于环形缓冲区） recvq waitq // 等待接收的 goroutine 队列（recv 阻塞队列） sendq waitq // 等待发送的 goroutine 队列（send 阻塞队列） // lock 保护 hchan 中的所有字段， // 以及阻塞在该 channel 上的 sudog 的多个字段。 // ⚠️ 在持有该锁时不要修改其他 G 的状态（尤其是不要唤醒 G）， // 否则可能与栈收缩操作发生死锁。 lock mutex } // 等待队列结构，用于接收和发送阻塞的 goroutine 链表 type waitq struct { first *sudog // 队首 goroutine last *sudog // 队尾 goroutine } 先来解释 maxAlign = 8 和 hchanSize = unsafe.</description></item><item><title>Base64</title><link>https://blog.121306.xyz/posts/golang/base64/</link><pubDate>Mon, 07 Apr 2025 16:30:25 +0800</pubDate><guid>https://blog.121306.xyz/posts/golang/base64/</guid><description>什么是 Base64 Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法。
HTTP 的全称是 HyperText Transfer Protocol（超文本传输协议），最初设计的目的确实是：
传输 超文本（HTML） 但实际上作为应用层协议，HTTP 可以传输任意类型的数据。
HTTP Header 不能直接放图片字节进去，只能用 ASCII 字符（Base64 就是 ASCII-safe） Email 内容（MIME 协议）SMTP 协议历史原因只支持 7-bit ASCII，不能发图片，怎么办？Base64！ JSON / XML 这些格式都是文本格式，不能放二进制文件进去，必须转 Base64 编码后作为字符串存放 Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24)，然后把6Bit再添两位高位0，组成四个8Bit的字节，也就是说，转换后的字符串理论上将要比原来的长1/3。
例如：
11111111,11111111,11111111 -&amp;gt; 00111111,00111111,00111111,00111111 知道了 byte 的表示，但是还需要一张表，作为 base64 的编码表。
base64 中的 64 表示 64 个字符：
// StdEncoding is the standard base64 encoding, as defined in RFC 4648. var StdEncoding = NewEncoding(&amp;#34;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&amp;#34;) // URLEncoding is the alternate base64 encoding defined in RFC 4648.</description></item><item><title>Pipe</title><link>https://blog.121306.xyz/posts/golang/pipe/</link><pubDate>Tue, 30 Jul 2024 15:46:00 +0800</pubDate><guid>https://blog.121306.xyz/posts/golang/pipe/</guid><description>Pipe io.pipe 结构
type pipe struct { wrMu sync.Mutex // 序列化写操作的互斥锁 wrCh chan []byte // 用于从写者向读者发送数据的通道 rdCh chan int // 用于从读者向写者发送读取字节数的通道 once sync.Once // 确保&amp;#39;done&amp;#39;通道只关闭一次 done chan struct{}// 用于指示管道关闭的通道 rerr onceError // 存储关闭时发生的读错误 werr onceError // 存储关闭时发生的写错误 } 第一个select语句检查管道是否已关闭，通过尝试读取p.done通道。如果管道已关闭，则返回错误。 第二个select语句等待从写者通过p.wrCh发送的数据或管道关闭。 如果收到数据，将数据复制到b，并通过p.rdCh将读取的字节数发送回写者。 如果管道没有关闭，则会阻塞，直到管道关闭。 如果管道关闭，则返回错误。 func (p *pipe) read(b []byte) (n int, err error) { select { case &amp;lt;-p.done: return 0, p.readCloseError() default: } select { case bw := &amp;lt;-p.wrCh: nr := copy(b, bw) p.</description></item></channel></rss>