对于一个结构体来说,可以通过同时实现多个接口的方法来实现多个接口,例如:

type Writer interface {
    Write()
}
type Closer interface {
    Close()
}
type WriteCloser struct{}

func (wc *WriteCloser) Write() {
    fmt.Println("write")
}

func (wc *WriteCloser) Close() {
    fmt.Println("close")
}

func main() {
    var It1 Writer = &WriteCloser{}
    It1.Write()
    var It2 Closer = &WriteCloser{}
    It2.Close()
}

运行之后的结果是:

write
close

对于一个接口来说,可以通过接口字段组合实现不同的行为,也叫做接口嵌入。例如:

type Writer interface {
    Write()
}
type WriteCloser struct{
    Writer
}
type writedatabase struct {}
type writefile struct {}
func (wd *writedatabase) Write() {
    fmt.Println("write to database")
}
func (wf *writefile) Write() {
    fmt.Println("write to file")
}
func main() {
    var wc = &WriteCloser {
        &writedatabase{},
    }
    wc.Write()
    var wc2 = &WriteCloser {
        &writefile{},
    }
    wc2.Write()
}

运行之后的结果是:

write to database
write to file

在go中,使用panic来抛出一个错误并将程序停止。

一般有主动panic和被动panic两种情况。

对于主动panic,可以是当一个程序启动时如果需要的依赖程序没有启动就将这个启动停掉,比如没有开etcd或mysql等,例如:

func main() {
    ismysql := false; // 模拟mysql未启动的场景
    if !ismysql {
        panic("mysql 未启动")
    }
}

运行之后会得到如下结果:

panic: mysql 未启动

goroutine 1 [running]:
main.main()
        C:/gostudy/20250704/exe1/exe1.go:6 +0x25
exit status 2

对于被动panic的情况,如果不想要让程序退出可以使用recover来接受这个panic,之后可以选择打印或者做其他处理,并且程序是保持运行的。例如:

var mp map[string]string

func A() {
    defer func() {
        r := recover()
        fmt.Println("捕获到panic", r)
    }()
    mp["heky"] = "heky" // 在不用make或者初值初始化的情况下程序会报panic
}

func main() {
    A()
    fmt.Println("程序继续运行,未退出")
}

运行之后会得到如下结果:

捕获到panic assignment to entry in nil map
程序继续运行,未退出

这里需要注意的是如果要使用recover来捕获panic,recover必须在一个defer后面跟着的匿名函数中,并且这个recover必须在panic之前(因为在panic之后就是不可达的)。

假如说有一个需求就是每次访问一个函数之后都会获得一个变量递增之后的值,并且可以随时将这个变量的值清零。

如果想要做到前半部分的需求,我们可以使用全局变量。例如

var idx int

func getidx() int {
    idx += 1
    return idx
}

func main() {
    for range 5 {
        fmt.Println(getidx())
    }
}

之后想要完成第二个需求也可以通过将idx赋值为0来实现。

除了全局变量之外,还可以使用go函数闭包的特性来实现。例如:

func getidx() func() int {
    idx := 0
    return func() int {
        idx += 1
        return idx
    }
}

func main() {
    id := getidx()
    for range 5 {
        fmt.Println(id())
    }
}

此时假如想要将值清零可以重新调用getidx,获取一个新的函数的句柄,然后调用新获取的函数的句柄。例如:

func main() {
    // ... 省略上面内容
    id2 := getidx()
    for range 3 {
        fmt.Println(id2())
    }
}

运行之后的结果应该如下所示:

1
2
3
4
5
1
2
3

通过上面的例子可以看出和使用全局变量的方式相比,函数闭包的实现可以不依赖于一个专门的变量,这对于后面有多个线程同时需要使用到idx时可以避免发生堵塞和竞争。

在go中定义一个函数之后,对于形参的长度是可以变换的。通常对于可以变化长度的形参后面加上三个点 ... ,并且此时这个参数就变为了一个切片,例如:

func add(items ...int) (sum int) {
    for _, v := range items {
        sum += v;
    }
    return
}

对于这个函数来说,实现了将多个传入的int类型的参数进行相加的功能。

我们可以这样来使用

sum := add(1, 2, 3)
println(sum)

在这个例子中add函数传入了三个参数,那么 items 此时等价于 [1,2,3]

通过调试也可以看出这一点

image-20250703140119086

后端有点问题一直拖到现在,学长在摸鱼,我也闲着无聊先去看下。

主要是python脚本没有跑起来。

  1. 看下原来的代码在哪个地方用到python

我发现之前上传的是我有改过的,可能是因为我有部分的地方改过所以导致了用不了

服务器上面是没有安装python3.11的,所以得装一个python3.11

问了一下gpt,直接就是下了源码然后编译,目前来看还算是比较顺利

离线安装的依赖版本和本地的python版本一致

因为我电脑上的是3.12,服务器上需要的是3.11

所以之前本地打包的依赖服务器的安装不了

现在得先在本地启一个3.11的虚拟环境然后在虚拟环境下再来下载这些依赖

先是用scoop安装一下python311

scoop bucket add versions
scoop install versions/python311

然后创建一个虚拟环境

python311 -m venv py311env

然后激活虚拟环境(我用的是git bash)

source py311env/Scripts/activate

之后再下载依赖

mkdir my_pkgs
cd my_pkgs

pip download pandas scikit-learn keras numpy openpyxl matplotlib mysql-connector-python

然后打包成tar,在服务器上解压,再用pip安装

pip3 install --no-index --find-links=. pandas scikit-learn keras numpy openpyxl matplotlib mysql-connector-python

有点尴尬,忘记了电脑是windows,下的依赖只能是windows用不能给linux用

现在是打算用wsl重复一下上面的步骤

wsl上面需要还是手动编译一个python3.11

先要安装一下编译的依赖:

sudo su # 获取权限
sudo apt-get update
# 随文章进行而更新,依赖应该是全的
sudo apt-get install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget

然后就是编译安装

cd /opt
wget https://www.python.org/ftp/python/3.11.9/Python-3.11.9.tgz # 下载python
tar -xzf Python-3.11.9.tgz
cd Python-3.11.9

# 安装编译依赖(如果有权限,可以让管理员预装)
# CentOS: yum groupinstall "Development Tools"
# Debian/Ubuntu: apt-get install build-essential

# 编译并安装到自定义目录(不要覆盖系统 Python 2.7)
sudo ./configure --prefix=/opt/python3.11 --enable-optimizations
sudo make -j$(nproc)    # 编译时间较长
sudo make install

配置环境变量:

# 加入环境变量
echo 'export PATH=/opt/python3.11/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

# 验证版本
python3 --version

目前来说还算顺利

后面下载依赖的时候不知道为什么还是下的3.12的版本,可能pip直接安装是这样的?不懂,还是得建一个虚拟环境试下

创建虚拟环境失败,其实之前编译的时候有问题,但是我直接给忽略了,现在看来应该是编译出问题了,感觉wsl好像什么都没有。

问了一个gpt报错,说是因为少了依赖,先下完依赖之后再更新

还是得建一个虚拟环境,不过python的安装倒是顺利,不错。

目前好像是因为说内网的那个linux的版本比较老,一些包不支持,所以得专门下载低版本去安装希望顺利

可以先查看一下支持哪些平台

python3 -m pip debug --verbose

然后对于某一个包可以指定平台下载,例如:

pip download \
  --only-binary=:all: \
  --platform manylinux2014_x86_64 \
  --python-version 311 \
  --implementation cp \
  --abi cp311 \
  Pillow==10.0.1

目前都挺顺利的,但是到了要运行的时候发现内部少了Python 标准库模块 ctypes

应该是编译的问题,问了一下gpt说是服务器少了libffi 开发依赖
所以现在是先让那边的管理员看能不能解决,或者干脆帮忙装一下python3.11,唉。

至少可以先停一会儿了。

后面因为连不了网,他们那边也是没有解决方法,只能是我这里继续。

我查了一下linux版本是Centos7,然后网上找了一个rpm的包

https://ftp.iij.ad.jp/pub/linux/centos-vault/centos/7.7.1908/cr/x86_64/Packages/

https://ftp.iij.ad.jp/pub/linux/centos-vault/centos/7.7.1908/cr/x86_64/Packages/libffi-devel-3.0.13-19.el7.x86_64.rpm

本地安装了一下这个依赖,然后再重新编译,目前貌似没有什么问题,一切顺利

sudo yum install ./*.rpm

装好了之后,重新编译python3之后又运行了一遍脚本,然后补装了一个库,总归是可行了。

之后就是把服务重新启动一下,过一两天看下数据库的数据,如果没有问题的话,这个就解决了,可喜可贺,可喜可贺。