乐趣区

关于后端:几种Go版本管理工具

缘起:

编译上面这段代码时, 在 Mac 上没有什么问题, 失常运行,

<details>
<summary> 点击查看代码:</summary>

package main

import (
    "bytes"
    "encoding/binary"
    "encoding/json"
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "time"
)

func main() {http.HandleFunc("/register", deal) // 设置拜访的路由

    fmt.Println("1111:", 2222)

    err := http.ListenAndServe(":8088", nil) // 设置监听的端口
    if err != nil {log.Fatal("ListenAndServe:", err)
    }

}

func deal(w http.ResponseWriter, r *http.Request) {

    // Golang: 接管 GET 和 POST 参数 https://www.cnblogs.com/liuhe688/p/11063945.html
    // 依据申请 body 创立一个 json 解析器实例
    decoder := json.NewDecoder(r.Body)
    // 用于寄存参数 key=value 数据
    var params map[string]string

    // 解析参数 存入 map
    decoder.Decode(&params)

    name := params["name"]

    rand.Seed(time.Now().UnixNano())

    key := crack(name)

    fmt.Println("name:", name, "key:", crack(name))

    fmt.Fprintf(w, key) // 这个写入到 w 的是输入到客户端的

}

const (
    rounds    = 12
    roundKeys = 2 * (rounds + 1)
)

func crack(text string) string {name := []byte(text)
    length := len(name) + 4
    padded := ((-length) & (8 - 1)) + length
    bs := make([]byte, 4)
    binary.BigEndian.PutUint32(bs, uint32(len(name)))
    buff := bytes.Buffer{}
    buff.Write(bs)
    buff.Write(name)

    var ckName int64 = 0x7a21c951691cd470
    var ckKey int64 = -5408575981733630035
    ck := newCkCipher(ckName)
    outBuff := bytes.Buffer{}

    for i := 0; i < padded; i += 8 {bf := buff.Bytes()[i : i+8]
        buf := bytes.NewBuffer(bf)
        var nowVar int64
        if err := binary.Read(buf, binary.BigEndian, &nowVar); err != nil {panic(err)
        }

        dd := ck.encrypt(nowVar)

        outBuff.WriteByte(byte(dd >> 56))
        outBuff.WriteByte(byte(dd >> 48))
        outBuff.WriteByte(byte(dd >> 40))
        outBuff.WriteByte(byte(dd >> 32))
        outBuff.WriteByte(byte(dd >> 24))
        outBuff.WriteByte(byte(dd >> 16))
        outBuff.WriteByte(byte(dd >> 8))
        outBuff.WriteByte(byte(dd))

    }
    var n int32
    for _, b := range outBuff.Bytes() {n = rotateLeft(n^int32(int8(b)), 0x3)
    }
    prefix := n ^ 0x54882f8a
    suffix := rand.Int31()
    in := int64(prefix) << 32
    s := int64(suffix)
    switch suffix >> 16 {
    case 0x0401:
    case 0x0402:
    case 0x0403:
        in |= s
        break
    default:
        in |= 0x01000000 | (s & 0xffffff)
        break
    }

    out := newCkCipher(ckKey).decrypt(in)

    var n2 int64
    for i := 56; i >= 0; i -= 8 {n2 ^= int64((uint64(in) >> i) & 0xff)
    }

    vv := int32(n2 & 0xff)
    if vv < 0 {vv = -vv}
    return fmt.Sprintf("%02x%016x", vv, uint64(out))
}

type ckCipher struct {rk [roundKeys]int32
}

func newCkCipher(ckKey int64) ckCipher {ck := ckCipher{}

    var ld [2]int32
    ld[0] = int32(ckKey)
    ld[1] = int32(uint64(ckKey) >> 32)

    ck.rk[0] = -1209970333
    for i := 1; i < roundKeys; i++ {ck.rk[i] = ck.rk[i-1] + -1640531527
    }
    var a, b int32
    var i, j int

    for k := 0; k < 3*roundKeys; k++ {ck.rk[i] = rotateLeft(ck.rk[i]+(a+b), 3)
        a = ck.rk[i]
        ld[j] = rotateLeft(ld[j]+(a+b), a+b)
        b = ld[j]
        i = (i + 1) % roundKeys
        j = (j + 1) % 2
    }
    return ck
}

func (ck ckCipher) encrypt(in int64) int64 {a := int32(in) + ck.rk[0]
    b := int32(uint64(in)>>32) + ck.rk[1]
    for r := 1; r <= rounds; r++ {a = rotateLeft(a^b, b) + ck.rk[2*r]
        b = rotateLeft(b^a, a) + ck.rk[2*r+1]
    }
    return pkLong(a, b)
}

func (ck ckCipher) decrypt(in int64) int64 {a := int32(in)
    b := int32(uint64(in) >> 32)
    for i := rounds; i > 0; i-- {b = rotateRight(b-ck.rk[2*i+1], a) ^ a
        a = rotateRight(a-ck.rk[2*i], b) ^ b
    }
    b -= ck.rk[1]
    a -= ck.rk[0]
    return pkLong(a, b)
}

func rotateLeft(x int32, y int32) int32 {return int32(x<<(y&(32-1))) | int32(uint32(x)>>(32-(y&(32-1))))
}

func rotateRight(x int32, y int32) int32 {return int32(uint32(x)>>(y&(32-1))) | int32(x<<(32-(y&(32-1))))
}

func pkLong(a int32, b int32) int64 {return (int64(a) & 0xffffffff) | (int64(b) << 32)
}

</details>

但到了 Linux 上, 就会报错:

# command-line-arguments
./http_register.go:113:15: invalid operation: uint64(in) >> i (shift count type int, must be unsigned integer)
./http_register.go:175:16: invalid operation: x << (y & (32 - 1)) (shift count type int32, must be unsigned integer)
./http_register.go:175:47: invalid operation: uint32(x) >> (32 - y & (32 - 1)) (shift count type int32, must be unsigned integer)
./http_register.go:179:24: invalid operation: uint32(x) >> (y & (32 - 1)) (shift count type int32, must be unsigned integer)
./http_register.go:179:47: invalid operation: x << (32 - y & (32 - 1)) (shift count type int32, must be unsigned integer)

而在 Mac 上进行穿插编译:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build 文件名.go

(如果呈现 GOROOT blabla 之类的, 执行go env -w GO111MODULE=off )

也没有什么问题

导致这种状况的起因, 可能因 Go 版本不同而导致

Mac 上的 Go 版本为 1.16, 而 Linux 上 Go 版本为 1.11


解决:

最后想看一下有没有在线的不同 Go 版本执行工具, 无果而终.

想到之前用 php 时, 用过 brew switch 来切换不同的 php 版本. 但搜寻之后发现, 这个命令被 brew 弃用了.

之前用过 node 版本工具nvm, 于是试图找寻 Go 有没有相似工具, 发现了 gvm.

装置 gvm

$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)

N.B. : 不同操作系统还须要装置所需依赖,如 Mac 须要执行 brew install mercurial 装置 mercurial。具体见原始我的项目

另外如果呈现“ERROR: Unrecognized command line argument: ‘use’”报错,可参考此文, 执行:

cp -rp .gvm/scripts/env/use .gvm/scripts/use
chmod 775 .gvm/scripts/use

装置 go 1.11

gvm install go1.11

抉择版本

gvm use go1.11

果然曾经变为 Go 1.11

在 Go 1.11 环境下执行, 果然呈现了和在 Linux 上 Go 1.11 下呈现的同样谬误


gvm 更多命令

查看版本

➜ gvm list

gvm gos (installed)

=> go1.11
   system

查看 Go 的所有版本 (版本来源于源码中的 tag 标签)

<details>
<summary> 点击查看 Go 所有版本:</summary>

 gvm listall

gvm gos (available)

   go1
   go1.0.1
   go1.0.2
   go1.0.3
   go1.1
   go1.1rc2
   go1.1rc3
   go1.1.1
   go1.1.2
   go1.2
   go1.2rc2
   go1.2rc3
   go1.2rc4
   go1.2rc5
   go1.2.1
   go1.2.2
   go1.3
   go1.3beta1
   go1.3beta2
   go1.3rc1
   go1.3rc2
   go1.3.1
   go1.3.2
   go1.3.3
   go1.4
   go1.4beta1
   go1.4rc1
   go1.4rc2
   go1.4.1
   go1.4.2
   go1.4.3
   go1.5
   go1.5beta1
   go1.5beta2
   go1.5beta3
   go1.5rc1
   go1.5.1
   go1.5.2
   go1.5.3
   go1.5.4
   go1.6
   go1.6beta1
   go1.6beta2
   go1.6rc1
   go1.6rc2
   go1.6.1
   go1.6.2
   go1.6.3
   go1.6.4
   go1.7
   go1.7beta1
   go1.7beta2
   go1.7rc1
   go1.7rc2
   go1.7rc3
   go1.7rc4
   go1.7rc5
   go1.7rc6
   go1.7.1
   go1.7.2
   go1.7.3
   go1.7.4
   go1.7.5
   go1.7.6
   go1.8
   go1.8beta1
   go1.8beta2
   go1.8rc1
   go1.8rc2
   go1.8rc3
   go1.8.1
   go1.8.2
   go1.8.3
   go1.8.4
   go1.8.5
   go1.8.5rc4
   go1.8.5rc5
   go1.8.6
   go1.8.7
   go1.9
   go1.9beta1
   go1.9beta2
   go1.9rc1
   go1.9rc2
   go1.9.1
   go1.9.2
   go1.9.3
   go1.9.4
   go1.9.5
   go1.9.6
   go1.9.7
   go1.10
   go1.10beta1
   go1.10beta2
   go1.10rc1
   go1.10rc2
   go1.10.1
   go1.10.2
   go1.10.3
   go1.10.4
   go1.10.5
   go1.10.6
   go1.10.7
   go1.10.8
   go1.11
   go1.11beta1
   go1.11beta2
   go1.11beta3
   go1.11rc1
   go1.11rc2
   go1.11.1
   go1.11.2
   go1.11.3
   go1.11.4
   go1.11.5
   go1.11.6
   go1.11.7
   go1.11.8
   go1.11.9
   go1.11.10
   go1.11.11
   go1.11.12
   go1.11.13
   go1.12
   go1.12beta1
   go1.12beta2
   go1.12rc1
   go1.12.1
   go1.12.2
   go1.12.3
   go1.12.4
   go1.12.5
   go1.12.6
   go1.12.7
   go1.12.8
   go1.12.9
   go1.12.10
   go1.12.11
   go1.12.12
   go1.12.13
   go1.12.14
   go1.12.15
   go1.12.16
   go1.12.17
   go1.13
   go1.13beta1
   go1.13rc1
   go1.13rc2
   go1.13.1
   go1.13.2
   go1.13.3
   go1.13.4
   go1.13.5
   go1.13.6
   go1.13.7
   go1.13.8
   go1.13.9
   go1.13.10
   go1.13.11
   go1.13.12
   go1.13.13
   go1.13.14
   go1.13.15
   go1.14
   go1.14beta1
   go1.14rc1
   go1.14.1
   go1.14.2
   go1.14.3
   go1.14.4
   go1.14.5
   go1.14.6
   go1.14.7
   go1.14.8
   go1.14.9
   go1.14.10
   go1.14.11
   go1.14.12
   go1.14.13
   go1.14.14
   go1.14.15
   go1.15
   go1.15beta1
   go1.15rc1
   go1.15rc2
   go1.15.1
   go1.15.2
   go1.15.3
   go1.15.4
   go1.15.5
   go1.15.6
   go1.15.7
   go1.15.8
   go1.15.9
   go1.15.10
   go1.15.11
   go1.15.12
   go1.16
   go1.16beta1
   go1.16rc1
   go1.16.1
   go1.16.2
   go1.16.3
   go1.16.4
   release.r56
   release.r57
   release.r58
   release.r59
   release.r60
   release.r57.1
   release.r57.2
   release.r58.1
   release.r58.2
   release.r60.1
   release.r60.2
   release.r60.3

</details>


其余计划 –IDE

不论对于 Python, 还是 Golang, 面对版本问题时, 应用 PyCharm 或 GoLand, 始终是极好的抉择

但当初只能下载最近几个版本,更长远的无奈装置


其余计划 –Docker

docker pull golang:1.xx

docker run -it --name golang-1.xx 自定义名称 golang:1.xx

进入到容器中(默认是基于 ubuntu 的镜像)

(如果没有 vi/vim)切换源,装置 vim

mv /etc/apt/sources.list /etc/apt/sources.list.bak

echo  "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free" >/etc/apt/sources.list

echo  "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free" >>/etc/apt/sources.list

echo  "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free" >>/etc/apt/sources.list

echo  "deb http://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free" >>/etc/apt/sources.list

apt-get update

apt-get install -y vim

这种形式是万能的,任何版本都能够失去 (然而都是 Linux 版本的~)


其余计划 –brew

但如果想用 Mac 的以往版本的 Go,用 Docker 形式做不到~

还能够用 brew

能够在这里找到所有能够装置的 Go 版本

(从 1.16 开始反对 m1)


问题解决

切换为 Go 1.11.5 版本后,IDE 会主动报错

y 为 int32, 将其强制转为uint32 即可,

i 为 int, 将其强制转为uint 即可.


参考:

如何灵便地进行 Go 版本治理


相似的工具还有 g

某位大佬举荐 gvc, 能治理很多种语言的版本

本文由 mdnice 多平台公布

退出移动版