(九)Go------捕获异常(defer,panic,revover)单元测试

树莓派5安装ROS1避坑指南:从系统配置到cmake报错全解决 本文详细介绍了在树莓派5上安装ROS1的完整流程,包括系统配置、环境变量设置、cmake报错解决等关键步骤。针对树莓派5的ARM架构特性,提供了从基础安装到高级调试的系统级解决方案,帮助开发者高效部署ROS1并避免常见编译陷阱。特别针对cmake报错问题,给出了深度解析和实用修复方法。 阅读详情

一. Go 捕获异常

不同于其他语言

引入了defer、panic、recover

defer和recover捕获异常

  1. Go程序抛出一个panic异常,在defer中通过recover捕获异常,然后处理
package main
import "fmt"
func test() {
    //在函数退出前,执行defer
    //捕捉异常后,程序不会异常退出
    defer func() {
        err := recover() //内置函数,可以捕捉到函数异常
        if err != nil {
            //这里是打印错误,还可以进行报警处理,例如微信,邮箱通知
            fmt.Println("err错误信息:", err)
        }
    }()
    //如果没有异常捕获,直接报错panic,运行时出错
    num1 := 10
    num2 := 0
    res := num1 / num2
    fmt.Println("res结果:", res)
}
func main() {
    test()
    fmt.Println("如果程序没退出,就走我这里")
}

二. Go 单元测试

  1. 写些程序用来检测产品代码的结果和预期的一样
  2. Go语言的测试依赖于go test测试命令和一组按约定方式编写的测试函数,测试命令可以运行这些测试函数。
  3. Go单元测试对文件名和方法名有严格的要求。
文件名必须以xx_test.go命名

方法必须是Test[^a-z]开头

方法参数必须 t *testing.T

使用go test执行单元测试

go test 常见参数

包含单元测试和性能测试

通过go help test可以看到go test的使用说明:
格式形如:
go test [-c] [-i] [build flags] [packages] [flags for test binary]
参数解读:
-c : 编译go test成为可执行的二进制文件,但是不运行测试。
-i : 安装测试包依赖的package,但是不运行测试。
关于build flags,调用go help build,这些是编译运行过程中需要使用到的参数,一般设置为空
关于packages,调用go help packages,这些是关于包的管理,一般设置为空
关于flags for test binary,调用go help testflag,这些是go test过程中经常使用到的参数
-test.v : 是否输出全部的单元测试用例(不管成功或者失败),默认没有加上,所以只输出失败的单元测试用例。
-test.run pattern: 只跑哪些单元测试用例
-test.bench patten: 只跑那些性能测试用例
-test.benchmem : 是否在性能测试的时候输出内存情况
-test.benchtime t : 性能测试运行的时间,默认是1s
-test.cpuprofile cpu.out : 是否输出cpu性能分析文件
-test.memprofile mem.out : 是否输出内存性能分析文件
-test.blockprofile block.out : 是否输出内部goroutine阻塞的性能分析文件
-test.memprofilerate n : 内存性能分析的时候有一个分配了多少的时候才打点记录的问题。这个参数就是设置打点的内存分配间隔,也就是profile中一个sample代表的内存大小。默认是设置为512 * 1024的。如果你将它设置为1,则每分配一个内存块就会在profile中有个打点,那么生成的profile的sample就会非常多。如果你设置为0,那就是不做打点了。
你可以通过设置memprofilerate=1和GOGC=off来关闭内存回收,并且对每个内存块的分配进行观察。
-test.blockprofilerate n: 基本同上,控制的是goroutine阻塞时候打点的纳秒数。默认不设置就相当于-test.blockprofilerate=1,每一纳秒都打点记录一下
-test.parallel n : 性能测试的程序并行cpu数,默认等于GOMAXPROCS。
-test.timeout t : 如果测试用例运行时间超过t,则抛出panic
-test.cpu 1,2,4 : 程序运行在哪些CPU上面,使用二进制的1所在位代表,和nginx的nginx_worker_cpu_affinity是一个道理
-test.short : 将那些运行时间较长的测试用例运行时间缩短

目录结构

test
      |
       —— calc.go
      |
       —— calc_test.go
//calc.go
package main
func add(a, b int) int {
    return a + b
}
func sub(a, b int) int {
    return a - b
}
//calc_test.go
package main
import (
    "testing"
)
func TestAdd(t *testing.T) {
    r := add(2, 4)
    if r != 6 {
        t.Fatalf("add(2, 4) error, expect:%d, actual:%d", 6, r)
    }
    t.Logf("test add succ")
}

结果

cd test/
ls
calc.go        calc_test.go
//-v参数显示通过函数的信息
yugoMBP:test yuchao$ go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
        calc_test.go:11: test add succ...is ok
PASS
ok      gostudy/gobook/test     0.006s

单元测试文件代码规则

1.文件名必须是_test.go结尾的,这样在执行go test的时候才会执行到相应的代码

2.你必须import testing这个包

3.所有的测试用例函数必须是Test开头

4.测试用例会按照源代码中写的顺序依次执行

5.测试函数TestXxx()的参数是testing.T,我们可以使用该类型来记录错误或者是测试状态

6.测试格式:func TestXxx (t *testing.T),Xxx部分可以为任意的字母数字的组合,
但是首字母不能是小写字母[a-z],例如Testintdiv是错误的函数名。

7.函数中通过调用testing.T的Error, Errorf, FailNow, Fatal, FatalIf方法,说明测试不通过,调用Log方法用来记录测试的信息。

练习

1. 数字阶乘

一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。

package main

import "fmt"

func factorial(i int) int {
    if i <= 1 {
        return 1
    }
    return i * factorial(i-1)
}

func main() {
    var i int = 7
    fmt.Printf("Factorial of %d is %d\n", i, factorial(i))
}

//输出结果:
Factorial of 7 is 5040

2. 斐波那契数列(Fibonacci)

这个数列从第3项开始,每一项都等于前两项之和。

package main

import "fmt"

func fibonaci(i int) int {
    if i == 0 {
        return 0
    }
    if i == 1 {
        return 1
    }
    return fibonaci(i-1) + fibonaci(i-2)
}

func main() {
    var i int
    for i = 0; i < 10; i++ {
        fmt.Printf("%d\n", fibonaci(i))
    }
}
//输出结果:
    0
    1
    1
    2
    3
    5
    8
    13
    21
    34

三. Go defer 延迟

程序开发中经常要创建资源(数据库初始化连接,文件句柄,锁等),在程序执行完毕都必须得释放资源,Go提供了defer(延时机制)更方便、更及时的释放资源。

  1. 内置关键字defer 用于延迟调用
  2. defer在return前执行,常用于资源释放
  3. 多个defer按 先进后出 的机制执行
  4. defer语句的变量,在defer声明时定义
  5. 显式 return 返回前,会先修改命名返回参数

defer用途:

  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放

defer 是先进后出
后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。

package main

import "fmt"

func main() {
    var whatever [5]struct{}

    for i := range whatever {
        defer fmt.Println(i)
    }
}
//结果
    4
    3
    2
    1
    0
package main
import (
    "fmt"
)
func testDefer1() {
    //defer机制 先入后出,如同羽毛球筒
    defer fmt.Println("hello v1") //顺序5
    defer fmt.Println("hello v2") //顺序4
    defer fmt.Println("hello v3") //顺序3
    fmt.Println("aaaaa")          // 顺序1
    fmt.Println("bbbb")           //顺序2
}
func testDefer2() {
    for i := 0; i < 5; i++ {
        //每次循环,defer将后入的语句压到defer栈
        //依旧先入后出
        defer fmt.Printf("i=%d\n", i)
    }
    fmt.Printf("running\n") //顺序1
    fmt.Printf("return\n")  //顺序2
}
func testDefer3() {
    var i int = 0
    //defer是声明时定义好的,之后再修改无效,因此i=0
    defer fmt.Printf("defer i=%d\n", i)
    i = 1000
    fmt.Printf("i=%d\n", i)
}
func main() {
    //testDefer1()
    //testDefer2()
    testDefer3()
}

1. 遇到了闭包

如果defer遇到了闭包

package main

import "fmt"

func main() {
    var whatever [3]struct{}
    for i := range whatever {
        defer func() { fmt.Println(i) }()
    }
}
//相当于
i结果最后为2,因为闭包原因,所以i最终为2
//结果,
2
2
2

package main

import "fmt"

type Test struct {
    name string
}

func (t *Test) Close() {
    fmt.Println(t.name, " closed")
}
func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        defer t.Close()
    }
}
//预计的输出c b a,而是输出c c c
//结果
    c  closed
    c  closed
    c  closed
将defer t.Close()改为defer Close(t)
输出结果:
    c  closed
    b  closed
    a  closed

省去函数,可以用t.Close()

package main

import "fmt"

type Test struct {
    name string
}

func (t *Test) Close() {
    fmt.Println(t.name, " closed")
}
func main() {
    ts := []Test{{"a"}, {"b"}, {"c"}}
    for _, t := range ts {
        t2 := t
        defer t2.Close()
    }
}
    c  closed
    c  closed
    c  closed

结论:
defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行。也就是复制了一份。但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待。

多个 defer 注册,按 FILO 次序执行 ( 先进后出 )。
异常也会输出

package main

func test(x int) {
    defer println("a")
    defer println("b")

    defer func() {
        println(100 / x) // div0 异常未被捕获,逐步往外传递,最后终止进程。
    }()

    defer println("c")
}

func main() {
    test(0)
}
//结果
	c
    b
    a
    panic: runtime error: integer divide by zero

*延迟调用参数在注册时求值或复制,可用指针或闭包 “延迟” 读取。

package main

func test() {
    x, y := 10, 20

    defer func(i int) {
        println("defer:", i, y) // y 闭包引用
    }(x) // x 被复制

    x += 10
    y += 100
    println("x =", x, "y =", y)
}

func main() {
    test()
}
输出结果:

    x = 20 y = 120
    defer: 10 120

*滥用 defer 可能会导致性能问题,例如:在一个 “大循环” 里。

package main

import (
    "fmt"
    "sync"
    "time"
)

var lock sync.Mutex

func test() {
    lock.Lock()
    lock.Unlock()
}

func testdefer() {
    lock.Lock()
    defer lock.Unlock()
}

func main() {
    func() {
        t1 := time.Now()

        for i := 0; i < 10000; i++ {
            test()
        }
        elapsed := time.Since(t1)
        fmt.Println("test elapsed: ", elapsed)
    }()
    func() {
        t1 := time.Now()

        for i := 0; i < 10000; i++ {
            testdefer()
        }
        elapsed := time.Since(t1)
        fmt.Println("testdefer elapsed: ", elapsed)
    }()

}
输出结果:

    test elapsed:  223.162µs
    testdefer elapsed:  781.304µs

2. defer陷阱

defer 与 closure

package main

import (
    "errors"
    "fmt"
)

func foo(a, b int) (i int, err error) {
    defer fmt.Printf("first defer err %v\n", err)
    defer func(err error) { fmt.Printf("second defer err %v\n", err) }(err)
    defer func() { fmt.Printf("third defer err %v\n", err) }()
    if b == 0 {
        err = errors.New("divided by zero!")
        return
    }

    i = a / b
    return
}

func main() {
    foo(2, 0)
}
输出结果:

    third defer err divided by zero!
    second defer err <nil>
    first defer err <nil>

解释:如果 defer 后面跟的不是一个 closure 最后执行的时候我们得到的并不是最新的值。

defer 与 return

package main

import "fmt"

func foo() (i int) {

    i = 0
    defer func() {
        fmt.Println(i)
    }()

    return 2
}

func main() {
    foo()
}
输出结果:

    2

解释:在有具名返回值的函数中(这里具名返回值为 i),执行 return 2 的时候实际上已经将 i 的值重新赋值为 2。所以defer closure 输出结果为 2 而不是 1。

实战:RK3568 Android14 点亮 LVDS 屏幕 4组数据 (D0~D3) + 1组时钟 (CLK)。最大支持 1280x800 @ 60Hz。8组数据 (Even03, Odd03) + 2组时钟。支持 1080P 及以上。/ {/* 背光与电源 *//** 关键配置:数据格式映射* 可选值: "jeida-18", "jeida-24", "vesa-24"* 6位屏选 xx-18, 8位屏选 xx-24* 颜色不对(偏色/底片效果)就换 VESA <-> JEIDA*/ 阅读详情

相关推荐

5分钟搞定:用Pyannote和Whisper实现带说话人分离的语音转文字(附完整代码)

本文详细介绍了如何快速构建一个集成了说话人分离功能的语音转文字系统。通过结合OpenAI的Whisper模型进行高精度语音识别和Pyannote模型实现说话人分离,并提供了完整的代码实现、环境搭建指南以及核心的对齐与合并逻辑,帮助开发者高效处理会议录音、访谈等多说话人音频,实现自动化转录。

threejs5artist的博客 635

go语言中异常的使用及捕获

如果存在一些不确定的异常我们应该捕获,并且执行对应的逻辑。其他语言中有try catch 那么go语言怎么来实现呢

shura1014的博客 1803

量化实战:用三种波动率模型给你的期货策略做个“体检”(附Python代码与螺纹钢案例)

本文深入探讨了三种专业波动率模型(Parkinson、Garman-Klass和Rogers-Satchell)在期货量化策略中的应用,并以螺纹钢期货为例,展示了如何通过Python实现这些模型进行多维度波动率分析。文章详细比较了不同模型的特点和适用场景,提供了动态仓位管理、止损策略优化等实战应用方案,帮助交易者更精准地评估市场风险,优化策略表现。

weixin_26824299的博客 460

【Go实战基础】Go 是如何捕获及处理异常的

目录 一、简介 二、数据结构 1、defer 2、panic 3、recover 三、菜鸟实战 1、创建 g007.go 2、编译和运行 3、运行结果 一、简介 Go 语言追求简洁优雅,不支持传统的 try - catch - finally 这种方式捕获和处理异常,Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得更加混乱。 在 Go 语言中,使用多值返回来返回错误,不要用异常代替错误,更不要用来控制流程。 在遇到真正的异常的情况下(比如除数为0了),才使用

菜鸟实战的博客 2820

国产HDMI2.0芯片GSV2011怎么选?手把手教你用它设计音视频采集卡(附FPGA/海思对接指南)

本文详细解析国产HDMI2.0芯片GSV2011在音视频采集卡设计中的应用,涵盖芯片选型、硬件设计要点及与FPGA/海思平台的对接指南。GSV2011凭借4K@60Hz支持、音频提取嵌入功能和高集成度,成为音视频设备的核心选择,助力开发者快速实现高性能采集卡设计。

weixin_30181209的博客 331

信息学奥赛一本通高手训练1680:序列

题目 代码 #include<cstdio> #include<iostream> #include<cmath> #define LL long long using namespace std; const LL N = 1400000+7; const LL mod = 1e9+7; int n, t; LL pos[N], sum[N], ans[N]; struct node{ LL ll, rr; }a[N]; int main(){ p

qingfeixueyue的博客 468

Go-异常处理(defer recover panic)

Go 语言在运行当中会出现panic ,为了解决和避免该问题学习defer,panic, recover 关键字略。

技术鱼的博客 1499

国产FPGA逆袭!深度评测复旦微RFVU3P5G核心板在相控阵雷达中的表现

本文深度评测了复旦微RFVU3P5G核心板在相控阵雷达中的实战表现。该核心板凭借射频直采架构、高采样率ADC/DAC及丰富的DSP资源,在多通道同步精度、动态范围及系统稳定性等关键指标上表现出色,展现了国产FPGA在高端雷达应用中的硬核实力与供应链自主价值。

b0c1d2的博客 722

Go 语言中的未知异常捕获

Go 通过defer和recover组合处理运行时恐慌来实现异常捕获,而非传统try - catch结构。阐述了其在单goroutine(如main函数内简单恐慌捕获)、多goroutine(worker函数在goroutine中异常处理)、函数调用链(lowerLevel向higherLevel传递异常)以及处理外部库(callThirdParty处理第三方库函数恐慌)等场景下的应用

ztt123654的博客 1053

中孚保密检查系统彻底卸载指南:绕过口令与清除内核残留

中孚保密检查系统是深度集成于Windows内核的合规管控软件,其卸载涉及用户态口令校验、内核态服务引擎与Ring 0级驱动自保三重机制。理解其基于SHA-256哈希的本地口令验证原理和zfsysflt.sys过滤驱动的加载逻辑,是实现无残留清理的技术前提。该系统具备高权限驻留特性,常规卸载工具无法触达驱动与服务层,易引发蓝屏、启动缓慢及新安全软件冲突等工程问题。典型应用场景包括涉密终端批量清退、安全研究环境重建及误装后紧急退出。本文聚焦‘口令绕过+手动清理’双轨方案,覆盖注册表、服务、驱动、文件与计划任务五

weixin_33508411的博客 954

基于全局和局部接受性因果特征的广义学习模型,用于在线增量机械故障诊断

本文提出了一种**因果广义学习模型(CBLM)**,用于在线增量机械故障诊断。该模型结合了**全局因果特征**(时域、频域、故障特征频率均值)和**多尺度局部因果特征**(通过扩张卷积提取),构建了一个具有**增量学习能力**的广泛学习系统(BLS)。CBLM支持**结构增量学习**(增加增强节点)和**样本增量学习**(动态更新权重),无需重新训练整个模型,显著提高了计算效率和诊断精度。在两个滚动轴承数据集上的实验表明,CBLM在诊断准确性和训练时间上均优于传统深度学习模型,适用于在线实时故障诊断。

huanghm88的专栏 387

go实现异常捕捉

go语言捕获异常办法

qq_43022682的博客 591

基于上下文的 Listwise 重排模型(一):miRNN

2018年阿里团队提出的miRNN(Mutual Influence aware RNN)模型,首次将电商搜索重排建模为全局优化问题,通过RNN捕捉商品序列的相互影响,结合Beam Search生成最优排序,在淘宝搜索中实现GMV(商品交易总额)提升5%的突破。本文将结合论文细节与通俗案例,拆解这一工业级重排框架的核心逻辑。

进一步有进一步的欢喜~ 1918

2024年最全(九)Go------捕获异常(defer,panic,revover)单元测试,上岸蚂蚁金服

如果你将它设置为1,则每分配一个内存块就会在profile中有个打点,那么生成的profile的sample就会非常多。-test.cpu 1,2,4 : 程序运行在哪些CPU上面,使用二进制的1所在位代表,和nginx的nginx_worker_cpu_affinity是一个道理。一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!-test.v : 是否输出全部的单元测试用例(不管成功或者失败),默认没有加上,所以只输出失败的单元测试用例。

2401_84790759的博客 1218

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

(九)Go------捕获异常(defer,panic,revover)单元测

num2 := 0res := num1 / num2fmt.Println(“res结果:”, res)}func main() {test()fmt.Println(“如果程序没退出,就走我这里”)}二. Go 单元测试=============================================================================写些程序用来检测产品代码的结果和预期的一样Go语言的测试依赖于go test测试命令和一组按约定方式编写的测试函数,测试命令可以运行这

Y1567409的博客 726

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【Go自学第八节】Go错误和异常捕获以及处理

Go错误和异常捕获以及处理、error

Weber's blog 1289

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Junit 单元测试之错误和异常处理

整体代码示例 首先,为了简化,我们让服务层就是简单的类,然后使用Id查找用户,这个和之前测试UserService接口不太一样哦:

人生不怕起点低,就怕没追求 1559

Go 语言异常处理

在 Java 和 C# 等编程语言中,错误处理通常是通过 try-catch 机制来管理的。当程序在 try 块中遇到错误时,catch 块会捕获该错误,并执行相应的处理逻辑。这种机制为处理异常提供了一种结构化的方法,确保即使在发生错误的情况下,应用程序也不会意外崩溃。 与此不同,Go 语言采用了一种完全不同的错误处理方式...

weixin_42517807的博客 480

Go语言的异常处理机制

defer(延迟执行):语句用于延迟执行一个函数调用,直到包含该defer语句的函数返回时才执行。在资源释放、日志记录等场景中尤为有用如果有多个defer语句,它们按后进先出(LIFO)顺序(先声明的后执行)defer语句的执行时机在函数返回之前,即使它位于return之后执行。panic(恐慌):用于触发一个运行时的错误,它可以在程序的任何地方引发,一旦触发,他会立刻停止当前函数的执行,并且开始回溯调用栈,直到遇到recover或者程序终止。recover。

2303_79710813的博客 1373

Go 项目实战:全局异常处理

在 Go 项目开发中,有效的异常处理是确保程序健壮性和稳定性的关键因素之一。全局异常处理机制能够统一处理项目中可能出现的各种异常情况,提高代码的可读性、可维护性以及错误处理的一致性。

Maisule的博客 179

Java 异常及解决方案系列(四):通过单元测试验证异常处理

单元测试是一种软件测试方法,通过对软件中的最小可测试单元进行验证,来检查其是否按预期工作。在 Java 中,JUnit 是最常用的单元测试框架之一。通过单元测试,你可以自动化地验证代码的正确性,包括异常处理逻辑。通过本文的介绍,你已经了解了如何通过 JUnit 编写单元测试来验证 Java 代码中的异常处理逻辑。通过单元测试,你可以确保代码在遇到异常时能够正确地处理,避免潜在的错误和崩溃。在实际开发中,编写全面的单元测试不仅有助于提高代码质量,还能在代码变更时提供可靠的回归测试。

阿里渣渣java研发组-群主 1743

常见方法的单元测试总结(junit+mocktio)

对于这段代码,我们需要根据它的功能来编写单元测试。这个代码段看起来是用来检查某个节点是否初始化,并且当发生异常时记录日志并返回。首先,我们需要确定nodeSelf()方法的返回值,两种思考,如果它返回null,那么代码会记录一条信息并返回。如果它抛出异常,代码会捕获这个异常,记录一条信息并返回。

m0_58168670的博客 1094

【Go语言基础【14】】defer与异常处理(panic、recover)

【Go语言基础【14】】defer与异常处理(panic、recover)

hiliang521的博客 1099

Go panic 与 recover 异常处理

异常处理 Golang 没有结构化异常,使用 panic 抛出错误,recover 捕获错误。 异常的使用场景简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。 panic 1、内置函数 2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行 3、...

爱死亡机器人 2381

【Golang】go语言异常处理快速学习

Go语言常见的异常处理知识大全,快速入门学习,形成整体知识架构,在实际中应用分析go语言异常处理的机制

2301_79819426的博客 1532

【GO语言卵细胞级别教程】07.捕获异常和自定义错误

Go语言中的错误处理主要通过返回错误值来实现,而不是像一些其他语言一样使用异常。Go的错误处理有一些独特的特性,以下是一些关于Go语言错误处理的要点:

5万+
上一篇: (八) Go------函数(init,包,闭包)
下一篇: redis内存问题
(─__─)
博客等级 码龄7年 1万+粉丝 255原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值