前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >不要迷信golang向下兼容

不要迷信golang向下兼容

作者头像
golangLeetcode
发布2023-12-14 10:23:50
1421
发布2023-12-14 10:23:50
举报

golang真的完全向下兼容吗?

我们从一个奇怪的bug说起。在后台应用有这么一个场景,将数据以xslx格式导出,方便产品运营通过excel来查看数据。golang中,我们常用的包是

代码语言:javascript
复制
github.com/tealeg/xlsx

突然有一天,发现导出的xlsx文件无法打开,报错如下

代码语言:javascript
复制
修复结果到 myfile0.xml
在文件“/Users/myfile.xlsx”中检测到错误
被替换的部件: 有 XML 错误的 /xl/worksheets/sheet1.xml。加载错误。行 2,列 1139。

xlsx的元数据被损坏了。首先怀疑是不是对象存储发生了故障,校验上传和下载的文件的md5是一样的,排除了这种可能。然后在本地起一个服务,发现文件可以照常下载。然后对比了下本地下载的文件md5和线上下载的md5发现是有差别的。对于同一份代码,我们只能从环境差异的角度来进行排查了。

对比发现线上版本

代码语言:javascript
复制
Now using version go1.21

本地版本

代码语言:javascript
复制
go version go1.19 darwin/amd64

两者使用的xlsx包都是

代码语言:javascript
复制
github.com/tealeg/xlsx v1.0.5

按照惯性思维,高版本golang是向下兼容低版本的,目前低版本没有问题,高版本是不太可能出问题的,但是偏偏又出现了兼容性问题。首先把线上版本降下来,发现问题解决了。说明真是版本兼容问题。

接着尝试简化代码,在两个版本的go环境里进行了复现,简化后的代码如下:

代码语言:javascript
复制
package main

import (
  "bytes"
  "fmt"
  "log"

  "github.com/tealeg/xlsx"
)

func main() {
  xlsFile := xlsx.NewFile()

  sheet, err := xlsFile.AddSheet("Responses")
  if err != nil {
    log.Fatal(err)
  }

  rowName := sheet.AddRow()
  cellLabelName := rowName.AddCell()
  cellLabelName.Value = "Name"

  rowName.AddCell().Value = "HELLO WORLD"

  err2 := xlsFile.Save("myfile.xlsx")
  if err2 != nil {
    log.Fatal(err2)
  }
}

在github上发现有人也遇到了同样问题,但是没有给出原因:

https://github.com/tealeg/xlsx/issues/784

为了定位真实原因,我们还是从excel的报错入手开始排查:

首先尝试把xlsx的元数据打印出来,看下两个版本的golang产生的元数据有什么差异。在github.com/tealeg/xlsx@v1.0.5/file.go +289行加一个打印语句。

代码语言:javascript
复制
fmt.Println(marshal(xSheet))

我们可以得到两个版本的meta文件go 1.19版本

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <sheetPr filterMode="false">
        <pageSetUpPr fitToPage="false"></pageSetUpPr>
    </sheetPr>
    <dimension ref="A1:B1"></dimension>
    <sheetViews>
        <sheetView windowProtection="false" showFormulas="false" showGridLines="true"
            showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true"
            showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1"
            colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100"
            workbookViewId="0">
            <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"></selection>
        </sheetView>
    </sheetViews>
    <sheetFormatPr defaultRowHeight="12.85"></sheetFormatPr>
    <cols>
        <col collapsed="false" hidden="false" max="1" min="1" style="1" width="9.5"></col>
        <col collapsed="false" hidden="false" max="2" min="2" style="1" width="9.5"></col>
    </cols>
    <sheetData>
        <row r="1">
            <c r="A1" s="1" t="s">
                <v>0</v>
            </c>
            <c r="B1" s="1" t="s">
                <v>1</v>
            </c>
        </row>
    </sheetData>
    <printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false"
        verticalCentered="false"></printOptions>
    <pageMargins left="0.7875" right="0.7875" top="1.05277777777778" bottom="1.05277777777778"
        header="0.7875" footer="0.7875"></pageMargins>
    <pageSetup paperSize="9" scale="100" firstPageNumber="1" fitToWidth="1" fitToHeight="1"
        pageOrder="downThenOver" orientation="portrait" usePrinterDefaults="false"
        blackAndWhite="false" draft="false" cellComments="none" useFirstPageNumber="true"
        horizontalDpi="300" verticalDpi="300" copies="1"></pageSetup>
    <headerFooter differentFirst="false" differentOddEven="false">
        <oddHeader>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12&amp;A</oddHeader>
        <oddFooter>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12Page &amp;P</oddFooter>
    </headerFooter>
</worksheet>

go 1.21版本

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <sheetPr filterMode="false">
        <pageSetUpPr fitToPage="false"></pageSetUpPr>
    </sheetPr>
    <dimension ref="A1:B1"></dimension>
    <sheetViews>
        <sheetView windowProtection="false" showFormulas="false" showGridLines="true"
            showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true"
            showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1"
            colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100"
            workbookViewId="0">
            <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"></selection>
        </sheetView>
    </sheetViews>
    <sheetFormatPr defaultRowHeight="12.85"></sheetFormatPr>
    <cols>
        <col collapsed="false" hidden="false" max="1" min="1" style="1" width="9.5"
            customWidth="true"></col>
        <col collapsed="false" hidden="false" max="2" min="2" style="1" width="9.5"
            customWidth="true"></col>
    </cols>
    <sheetData xmlns="">
        <row r="1">
            <c r="A1" s="1" t="s">
                <v>0</v>
            </c>
            <c r="B1" s="1" t="s">
                <v>1</v>
            </c>
        </row>
    </sheetData>
    <printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false"
        verticalCentered="false"></printOptions>
    <pageMargins left="0.7875" right="0.7875" top="1.05277777777778" bottom="1.05277777777778"
        header="0.7875" footer="0.7875"></pageMargins>
    <pageSetup paperSize="9" scale="100" firstPageNumber="1" fitToWidth="1" fitToHeight="1"
        pageOrder="downThenOver" orientation="portrait" usePrinterDefaults="false"
        blackAndWhite="false" draft="false" cellComments="none" useFirstPageNumber="true"
        horizontalDpi="300" verticalDpi="300" copies="1"></pageSetup>
    <headerFooter differentFirst="false" differentOddEven="false">
        <oddHeader>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12&amp;A</oddHeader>
        <oddFooter>&amp;C&amp;&#34;Times New Roman,Regular&#34;&amp;12Page &amp;P</oddFooter>
    </headerFooter>
</worksheet>

对比后我们发现diff在于

说明两个版本的xml的marshal方法有改动,导致新版本的元数据多了几个属性。对比下两个版本的golang源码,发现在go1.21版本里go1.21/src/encoding/xml/marshal.go +548行多了下面几行代码

代码语言:javascript
复制
if tinfo.xmlname != nil && start.Name.Space == "" &&
    len(p.tags) != 0 && p.tags[len(p.tags)-1].Space != "" {
    start.Attr = append(start.Attr, Attr{Name{"", xmlnsPrefix}, ""})
}

尝试着把go1.21 源码包里这几行代码注释掉,重新编译,然后下载发现可以打开了。

由此可以看出,虽然golang源码在版本迭代升级的时候,非常注重向下兼容性,但是一些扩展包对兼容性做得也不够好。导致了特定场景出现意想不到的bug,我们在升级golang版本的时候一定要仔细验证,否则很容易踩坑。不要迷信任何结论。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档