Home avatar

搬砖程序员带你飞

砖搬得多了,就能盖楼

Rust 编程语言 - 猜数字游戏

阅读Rust程序设计语言笔记

输入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 引入输入输出库到当前作用域
use std::io;

// 入口函数
fn main() {
    println!("Guess the number!");

    println!("Please input youer guess.");

    // let 创建的变量默认不可变
    // 通过增加 mut 制定变量可变
    // new 是关联函数(静态方法)
    // String::new() 申请一个可增长的字符串
    let mut guess = String::new(); 

    io::stdin()
        .read_line(&mut guess) // & 引用传递, mut 可变变量返回Result<usize, Error> (枚举类型)
        .expect("Failed to read line");

    // 占位打印
    println!("You guessed: {guess}")
}

cargo run 运行

Rust 编程语言 - 安装

阅读Rust程序设计语言笔记

安装

  • 下载rustup脚本,并安装 curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
  • 或者直接brew install rust安装
  • 通过 rustc --verison 查看是否成功
1
rustc 1.66.0 (69f9c33d7 2022-12-12) (built from a source tarball)

hello world

1
2
3
4
5
6
7
8
9
// file main.rs

// main 是函数入口
fn main() {

    // println! 有感叹号是 rust 的宏
    // ; 语句结尾
    println!("Hello, world!");
}

执行 rustc main.rs 编译,./main执行; 可以通过rustfmt 格式化代码

服务发现

调研结果

  • eureka 已不维护,排除
  • nacos,consul 都提供了丰富的功能。
    • nacos 健康检查是provider 心跳;consul 是服务端做心跳。
    • 都提供了dns, http api 的发现功能
    • 都有详细metrix监控能力
    • nacos 有命名空间,consul 开源版本不支持
    • 都可以做鉴权
    • 运维成本:都存在一定运维成本。
  • nacos, consul 都提供了 配置管理功能。
    • nacos watch 回调方式,使用的主动请求
  • core-dns 无需入侵代码。其他均有代码入侵
    • core-dns 不支持集群外的服务发现,其他服务支持
    • core-dns 对细粒度的心跳检测做的不太好。(比如针对某个接口的POST操作等)
  • 个人建议
    • 在K8S集群内部做服务发现,不建议引入其他服务发现的依赖,使用core-dns即可
    • 如果需要做集群外部的服务依赖,或者有特殊的心跳检查,建议使用nacos。

微服务重的服务发现模式

下图是微服务下的各类模式。其中,服务发现仅是各系统间沟通的一种模式。

Golang 最佳实践

Google Go 语言最佳实践 | 中文版本

命名

避免重复

  • 函数或方法名中可以省略如下字段:
    • 输入输出类型
    • 方法接收器类型
    • 输入输出是否为指针
  • 包的名字
  • 方法接收器的名字
  • 参数传递的变量名称
  • 返回值类型的名称和类型

命名惯例

  • 返回一个对象,一般以对象名命名(避免加Get)
  • 动作一般会加动作前缀
  • 如果涉及到不同的类型,会把类型放到函数末尾
    • 函数主版本,则可以省略类型

测试助手包

  • 原包名 + test
  • 简单测试,桩直接使用Stub 即可
  • 多个测试桩,按照测试行为命名
  • 多个类型,多个测试桩,需要明确,类型+Stub,方法要明确
  • 测试中局部变量,命名要能区分出真实、测试类型

遮蔽

  • 避免作用域遮蔽原有的上下文变量;而在作用域外又重新使用的情况
  • 不使用和标准库的包名相同的变量

Util 包

  • 不使用 util、helper、common 类似的包名
  • 考虑调用时如何使用

包的大小

  • 文件应该足够内聚,以便维护者可以知道哪个文件包含了什么功能
  • 文件应该足够小,以便一旦有了它,就很容易找到

导入

proto,stub文件导入

  • 包重命名为 pb,
  • 若多个包,加前缀

导入顺序:

  • 标准库导入;
  • 普通项目导入;
  • pb等导入;
  • 副作用导入;
  • 分组导入

错误处理

错误消费端:

  • 诊断信息,返回给人类;
  • 维护者使用;
  • 终端用户解释

错误定义:

  • 是否需要结构;
  • 考虑添加你拥有但调用者、被调用者没有的信息

使用errgroup;

错误值定义:

  • 哨兵模式,直接判等;
  • errors.Is() 方式包含error;
  • 结构化error,提供status字段

错误信息,不冗余;

  • 适当添加额外的信息使错误信息更有用;
  • 一般使用 fmt.Errorf(“xxx %w”) %w 会包装参数中的err;需要提供细节的err 一般会这么使用;
  • 链式,一次只能wrap一个err
  • 屏蔽细节,使用 fmt.Errorf(“xxx %v”)

日志中输出错误

  • 敏感数据问题
  • 尽量少使用log.Error

程序初始化

  • 初始化错误,应该传播到main,调用 log.Exit 退出,解释如何修复

程序检查和panic;

  • 尽量少用panic,倾向于返回错误,而不是终止程序;
  • panic的传导可能会影响上下文状态;

何时用panic,

  • 对api的误用,报panic;
  • 调用链中有一个对应的recover,确保panic 不跨越包。
  • 命令后解析之前,不调用日志函数

文档

参数与配置:

  • 不是每个参数都需要文档

只描述易出错和不明显的字段和参数

context

  • 惯例:取消操作,返回ctx.Err(),不需要注释;
  • 例外情况进行注释

是否支持并发的注释

清理,标记是否有后续的清理

godoc 格式化

  • 段落之间空行
  • 测试文件包含可运行代码
  • 缩进行增加两个空格,格式化代码
  • 可运行的代码,更好的方式是提供Example Case,而非注释
  • 一行以大写字母开始,除括号和逗号外不含标点符号,后面是另一个段落,这样的行将被格式化为标题

经常使用的 err != nil  ,如果判断 err==nil 增加注释强调

变量申明

初始化,非零值初始化,尽量使用 :=

非指针零值

  • 用申明而不是赋值
  • 锁不可复制的结构体字段,使用值类类型,用零值初始化,指针传递
  • 复合类型,函数返回,最好返回指针

复合字面值

  • 已知的参数,可以用复合字面值声明值

尺寸提示

  • 备注,提示容量内容。比如slice,map等
  • 性能敏感型尤为注意

channel

  • 尽可能指向channel方向,防止误操作

函数参数列表

  • 减少参数的数量,抽离出多个函数,或者使用一个未导出的实现
  • 参数过多,可以使用一个struct作为入参,或者variadic 技术

不定长参数 variadic 

复杂的命令行交互界面

  • cobra
  • subcommands

测试

把测试留给Test 函数

  • 测试case 正交
  • 数据类似,使用表驱动的测试
  • 在Test函数中内联逻辑

设计可扩展的验证APIs

字符串链接

简单情况,首选 +

需要格式化,选择 fmt.Sprintf / fmt.Fprintf

零散的字符串,使用strings.Builder()

用 `` 构建多行常量字符串

0%