RMSE(均方根误差)

测量预测过程中的预测错误的标准差。 公式 \[RMSE(X,h)=\sqrt{\frac{1}{m}\sum_{i=1}^{m}(h(x^{(i)}) - y^{(i)})^2}\] m 是你在测量 RMSE 时,所使用的数据集中实例的数量 \(x^{(i)}\) 是数据集中第 \(i\) 个实例的所有特征值的向量(标签特征除外),\(y{(i)}\) 是标签(也就是我们期待该实例的输出值) X 是数据集中所有实例所有特征值的矩阵(标记特征除外)。每个实例一行,也就是说第 \(i\) 行等于 \(x^{(i)}\) 的转置矩阵1,记作 \((x^{(i)})^T\) h 是系统的预测函数,也称为一个假设。当给定系统一个实例的特征向量 \(x^{(i)}\) ,他会输出一个预测值 \(\hat{y}=h(x^{(i)})\) RMSE(X,h) 是使用假设 h 在示例上测量的成本函数。 转置运算符会将列向量转换成行向量。 ↩︎

September 12, 2020 · 1 min · Gray King

机器学习涉及数学概念

公式 RMSE(均方根误差) MAE(平均绝对误差) 概念 标准差(Std Dev) 范数 方差 皮尔逊相关系数(标准相关系数) 线性相关性

September 12, 2020 · 1 min · Gray King

Python behind the scenes #1: how the CPython VM works

tags: Translate,Python 原文链接:Python behind the scenes #1: how the CPython VM works。 Python 幕后 #1: CPython 虚拟机如何工作 介绍(Introduction) 你是否曾经好奇过当你运行 Python 代码时 python 做了些什么? $ python script.py 这篇文章将开启一个系列来尝试解答这个问题。我们将深入 Python 最流行的实现 CPython 的内部。 通过深入 CPython 的内部我们将更深一层的去理解这门编程语言本身。这也是我们这个系列的最主要的目标。 如果你熟悉 Python 并且可以阅读 C 代码,但是对 CPython 源码本身没有太多的经验, 那么你可能非常适合本系列,并且对本系列感兴趣。 什么是 CPython 并且为什么有人想学习它(What CPython is and why anyone would want to study it) 我们首先来说明一些众所周知的事情。CPython 是用 C 编写的 Python 解析器。他是 Python 语言的众多实现 的一种,其他还有诸如 PyPy、Jython、IronPython 等。CPython 的独特之处在于它是 Python 的起源、维护时间最长也是最受欢迎的。 CPython 实现了 Python,但是 Python 是什么?最简单的一个答案可能是:Python 是一门编程语言。 当正确问相同的问题,那么答案将会更加明确:什么定义了 Python?Python 不像 C 语言有正式的规范, 但是与之相近的是 Python 语言参考(Python Language Reference),它以如下内容开始: ...

September 8, 2020 · 6 min · Gray King

机器学习测试与验证

将数据分成两部分:训练集和测试集,通常使用 80% 的数据进行训练,20% 的数据用来测试。 验证集 单独分出来一个保留集合作为验证集,防止调整模型和超参数拟合测试集的最佳模型。 交叉验证 为避免验证集浪费太多数据,交叉验证将训练集分成若干个互补子集,然后每个模型都通过这些子集的不同组合来 训练,之后用剩余的子集进行验证。

September 7, 2020 · 1 min · Gray King

机器学习的主要挑战

训练数据的数量不足 训练数据不具代表性 质量差的数据 无关特征 特征工程 一个成功的机器学习项目,关键部分是提取一组好的用了训练的特征集,这个过程叫做特征工程。 特征选择 特征提取 通过手机数据创造新的特征 训练数据过度拟合 在模型的训练数据上表现良好,但是泛化时却不尽人如意。 解决方法 简化模型 收集更多的训练数据 减少训练数据中的噪声(修复数据错误和消除异常值) 正则化 通过约束模型使其更简单,并降低过度拟合风险。 超参数 通过调整超参数来调整应用正则化的程度。调整超参数是构建机器学习系统的非常重要的组成部分。 训练数据拟合不足 解决方法: 选择一个带有更多参数、更强大的模型 给学习算法提供更好的特征集 减少模型中的约束(如减少正则化超参数)

September 7, 2020 · 1 min · Gray King

机器学习系统的种类

监督式/无监督式学习 监督式学习 定义 训练数据经过标注包含素所需解决方案(标签或标记) 相关算法 K-邻近算法 线性回归 逻辑回归:广泛用于分类,输出“属于某个给定类别的概率”的值 支持向量机 决策树和随机森林 神经网络 适应场景 分类任务 预测变量 无监督式学习 定义 训练数据未经标注 相关算法 聚类算法 K-平均算法 分层聚类分析 最大期望算法 可视化和降维 主成分分析 核主成分分析 局部线性嵌入 t-分布随机临近嵌入 关联规则学习 Apriori Eclat 适应场景 通过聚类算法检测相似(层次聚类算法精度更高,可以再次细分) 可视化算法 降维:不丢失太多信息的前提下简化数据,方法之一是合并特征,过程叫做特征提取 异常检测:判断新的输入是正常还是异常,数据初筛、防作弊等 关联规则学习:发现属性之间有趣的联系 半监督式学习 大量未标记数据和少量标记数据进行学习。 强化学习 观察环境、作出选择、执行操作、并获得回报(负值则为惩罚)。 批量学习和在线学习 在数据流中进行增量学习。 批量学习 在线学习 在线学习也称为增量学习,同时支持恢复到上一状态,便于检测到性能下降及时中断和回滚。 核外学习 超大数据集超出一台计算机的主存储器,每次加载部分数据并不断重复直至完成训练。 学习率 学习率高系统迅速适应新数据,同时快速忘记老数据,学习率低则反之。 基于实例和基于模型的学习 基于实例的学习 系统完全记住学习示例,然后通过某种相似度度量方式将其泛化到新的实例。 基于模型的学习 模型选择 观察数据得出模型的过程。 衡量模型表现 定义效用函数(或适应度函数)来衡量模型有多好 定义成本函数来衡量模型有多差 线性回归通常选择成本函数来衡量线性模型的预测和训练实例之间的差距。 线性回归算法的意义所在:通过你提供的训练样本,找出最符合所提供数据的线性模型的参数,这就是训练过程。

September 7, 2020 · 1 min · Gray King

《机器学习实战》读书笔记

概览 机器学习系统的种类 机器学习的主要挑战 机器学习测试与验证 模型是观察的简化。 相关数学概念 机器学习涉及数学概念

September 5, 2020 · 1 min · Gray King

Machine Learning

scikit-learn 提供一些常见的机器学习算法 逻辑回归(Logistic Regression aka LR) 线性分类器 XGBoost 提供随机森林解决逻辑回归特征不明显的问题

September 3, 2020 · 1 min · Gray King

Rust Obscure Words for non-native English speakers

tags: Rust,Learning English unwinding

August 29, 2020 · 1 min · Gray King

Rust Asynchronous Programming

tags: Rust Future async fn 将一个代码块转换为一个 Future 对象, Future 对象维护一个状态机 Future 对象必须运行在一个 Executor 上 Executor futures::executor::block_on 阻塞当前线程直到 future 完成 // `block_on` blocks the current thread until the provided future has run to // completion. Other executors provide more complex behavior, like scheduling // multiple futures onto the same thread. use futures::executor::block_on; async fn hello_world() { println!("hello, world!"); } fn main() { let future = hello_world(); // Nothing is printed block_on(future); // `future` is run and "hello, world!" is printed } await await 异步的等待 future 完成,不阻塞当前线程,可以配合 futures::join! 可以同时 await 多个 future futures::try_join! 如果其中一个子 future 返回错误则立即返回(join! 需要等所有 future 全部返回) futures::select! 任意一个 future 完成则立即返回 async fn learn_and_sing() { // Wait until the song has been learned before singing it. // We use `.await` here rather than `block_on` to prevent blocking the // thread, which makes it possible to `dance` at the same time. let song = learn_song().await; sing_song(song).await; } async fn async_main() { let f1 = learn_and_sing(); let f2 = dance(); // `join!` is like `.await` but can wait for multiple futures concurrently. // If we're temporarily blocked in the `learn_and_sing` future, the `dance` // future will take over the current thread. If `dance` becomes blocked, // `learn_and_sing` can take back over. If both futures are blocked, then // `async_main` is blocked and will yield to the executor. futures::join!(f1, f2); } fn main() { block_on(async_main()); }

August 28, 2020 · 2 min · Gray King

Go Swagger 实现代码即文档

tags: Go 目标 当跟随这篇文章完成后将产出如下内容: 代码 http://gitlab.17zuoye.net/vgo/go-swagger-example 文档 http://swagger.17zuoye.net/?url=http%3A%2F%2F10.200.242.61%3A9090%2Fswagger.json 准备 Go1.14 及以上版本 安装 go-swagger :参见 官方文档。 接下来使用 gin 框架作为示例,如果之前没接触过可以先了解下该框架 创建一个项目 $ mkdir go-swagger-example $ cd go-swagger-example/ $ go mod init gitlab.17zuoye.net/vgo/go-swagger-example 开始使用 首先在你的 `main.go` 定义 go generate 像下面这样: //go:generate swagger generate spec -o ./swagger.yml package main func main() { println("Hello world!"); } 此时如果运行 go generate 在项目目录下就会生成一个 swagger.yml 文件: paths: {} swagger: "2.0" 使用单独的包托管 swagger 相关定义 在之前实践的过程中发现,如果在多个包中定义了相同名称的结构体会到只一个结构体覆盖另外一个结构体的定义。 所以为了解决这个问题,我把所有 swagger 相关的定义都放在同一个包下来避免相同名字的结构体。 创建 swagger/swagger.go 填充如下内容: // Package swagger defines API documentation. // // Swagger 演示后端接口 // // Schemes: http // Host: 10.200.242.35:8080 // BasePath: /api/ // Version: 0.1.0 // Contact: 王会<hui.wang.a@17zuoye.com> // // Consumes: // - application/json // // Produces: // - application/vnd.17zuoye.v1+json // // swagger:meta package swagger 上面文件通过注释来定义了一些接口相关的信息,包括: ...

August 28, 2020 · 5 min · Gray King

MySQL forget password

tags: MySQL 启动 mysqld 时加上 --skip-grant-tables 参数可以无密码进入 MySQL。

August 27, 2020 · 1 min · Gray King

MVCC

tags: MySQL https://liuzhengyang.github.io/2017/04/18/innodb-mvcc/ 来自《高性能 MySQL》: InnoDB 在每一行都隐式的多存储两个字段: 事务更新版本 事务删除版本 当事务开始时记录这两个版本,在读取的时候根据 Undo Log 和 Redo Log 来实现隔离级别的控制。序列化隔离级别下只能通过行锁来保证。 在可重复读隔离级别下: 首先判断事务更新版本是否大于事务开始前的版本 如果大于则根据 Undo Log 进行回退实现可重复读,这样在同一事务下不管读多少遍读取到的内容都是一样的。 可重复读隔离即便下无法避免幻读:即一开始没有读取到,随着其他插入事务的提交在同一事务里执行查询又能读取到的情况。

August 27, 2020 · 1 min · Gray King

MySQL grant subnet

tags: MySQL,Network https://stackoverflow.com/a/38389851/2873718 MySQL 授权用户子网段需要使用: 172.16.0.0/255.240.0.0 而不能使用 172.16.0.0/12

August 27, 2020 · 1 min · Gray King

Network

August 27, 2020 · 0 min · Gray King

逻辑右移

位移产生的空白填上 0,会导致有符号的负数变成正数。

August 2, 2020 · 1 min · Gray King

算数右移

位移的产生的空白填上符号位。

August 2, 2020 · 1 min · Gray King

汇编

tags: Computer Systems,《深入理解计算机系统》读书笔记 程序编码 $ gcc -Og -S mstore.c # outputs mstore.s $ gcc -Og -c mstore.c # outptus mstore.o $ objdump -d mstore.o 所有以 ‘.’ 开头额行都是指导汇编器和链接器工作额伪指令。 数据格式 C 声明 Intel 数据类型 汇编代码后缀 大小(字节) char 字节 b 1 short 字 w 2 int 双字 l 4 long 四字 q 8 char* 四字 q 8 float 单精度 l 4 double 双精度 q 8 访问信息 寄存器 一个 x86-64 的中央处理单元(CPU)包含一组 16 个存储 64 位值的 通用目的寄存器 。 四字 双字 字 字节 用途 %rax %eax %ax %al 返回值 %rbx %ebx %bx %bl 被调用者保存 %rcx %ecx %cx %cl 第四个参数 %rdx %edx %dx %dl 第三个参数 %rsi %esi %si %sil 第二个参数 %rdi %edi %di %dil 第一个参数 %rbp %ebp %bp %bpl 被调用者保存 %rsp %esp %sp %spl 栈指针 %r8 %r8d %r8w %r8b 第五个参数 %r9 %r9d %r9w %r9b 第六个参数 %r10 %r10d %r10w %r10b 调用者保存 %r11 %r11d %r11w %r11b 调用者保存 %r12 %r12d %r12w %r11b 被调用者保存 %r13 %r13d %r13w %r13b 被调用者保存 %r14 %r14d %r14w %r14 被调用者保存 %r15 %r15d %r15w %r15 被调用者保存 相关规则: ...

August 2, 2020 · 3 min · Gray King

IEEE 浮点数

tags: Computer Systems,《深入理解计算机系统》读书笔记 浮点数小数表示形式 .0111 = \(0x2^{-1}+2^{-2}+2^{-3}+2^{-4}\) IEEE 浮点数表示形式 \[ V=(-1)^s X M X 2^E \] s = 0 表示负数, s = 1 表示正数 M 是二进制表示的小数 E 是阶码 浮点数二进制组成 一个单独符号位 s 表吗符合 k 位阶码字段 exp 编码阶码 E n 位小数字段 frac 编码尾数 M 两种常见的格式 float s = 1 k = 8 n = 23 double s = 1 k = 11 n = 52 三种计算方式 前置的一些值 e 是 exp 位表示的无符号数 f 是 frac 位表示的小数 \(Bias = 2^{k-1} -1\) 规格化的值 规则:阶码字段 exp 的位模式即不全为 0,也不全为 1(单精度 255,双精度 2047) 计算方式 \(E = e - Bias\) $M = 1 + f $ 非规格化的值 规则:阶码字段 exp 全是 0(用于表示 0) 计算方式 \(E = 1 - Bias\) \(M = f\) 可以表示 +0 和 -0。 ...

August 2, 2020 · 1 min · Gray King

Choosing a Rust web framework, 2020 edition

tags: Rust source: Choosing a Rust web framework, 2020 edition

July 10, 2020 · 1 min · Gray King

SSH

SSH Port Forwarding -L 将远端机器的端口映射到本地 -R 将本地端口映射到远端

July 7, 2020 · 1 min · Gray King

Fearless Concurrency with Rust

tags: Rust 原文链接:https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html

July 3, 2020 · 1 min · Gray King

Rust Means Never Having to Close a Socket

tags: Translate,Rust,Rust Wrapper Types 原文链接:Rust Means Never Having to Close a Socket Rust 最酷的特性之一就是它可以自动地帮助你管理资源,同时在仍能保持安全(没有段错误)和高性能。 这是因为 Rust 是一门与众不同地编程语言,要理解我说的可能有点困难,让我来更近一步说明: Rust 就像带垃圾回收的编程语言,你无需手动释放内存 Rust 不同于其他带垃圾回收的编程语言,你无需1手动关闭或者释放像文件、套接字和锁这样的资源 Rust 达到以上这些特性不附带任何运行时开销(垃圾回收或者引用计数),并且不牺牲安全性。 如果你曾经造成过一个套接字或者文件泄漏,或者使用过一些抽象方法造成了这些资源的泄漏,那么你就会知道这有多重要。 你可能已经期望通过“使用后释放”来避免内存问题,而与此同时你并没有考虑到没有明确地关闭套接字可能出现类似的错误。我在这里告诉你,还有更好地办法。 如果你使用的是带垃圾回收的编程语言,则应密切关注本文提到的资源管理方面的内容。如果你使用的是像 C/C++ 这样底层编程语言,你可能会对安全方面更加感兴趣。 Rust 的许多特性都是从其他语言借鉴而来。Rust 之所以变得有趣是因为它把所有的这些特性放在了一起,并且在编程语言层面实现了更严格地保证。 实际上,这种编程语言层面的保证让这些特性更加实用。 所有权系统(The Ownership System) 让这种保证工作的方式是通过 Rust 的「所有权(ownership)」系统。不管任何时候你创建一个新的对象,都被创建它的「作用域(scope)」所拥有。 让我们通过一个例子来进一步说明:我们定义一个函数,函数拷贝输入文件到临时文件去处理它,然后拷贝输入文件到输出文件。 fn process(from: &Path, to: &Path) -> IoResult<()> { // creates a new tempdir with the specified suffix let tempdir = try!(TempDir::new("skylight")); // open the input file let mut from_file = try!(File::open(from)); // create a temporary file inside the tempdir let mut tempfile = try!(File::create(&tempdir.path().join("tmp1"))); // copy the input file into the tempfile try!(io::util::copy(&mut from_file, &mut tempfile)); // use an external program to process the tmpfile in place // after processing, copy the tempfile into the output file let mut out = try!(File::create(to)); io::util::copy(&mut tempfile, &mut out) } 在这个例子中,函数 process 的作用域再第一行创建了 TempDir 是其初始拥有者。在这个例子中, process 函数从未放弃所有权,所以当函数完成调用, 它就会自动被丢弃(dropped),也就是会删除 Tempfile 。 ...

June 29, 2020 · 4 min · Gray King

Rust 并发

并发 std::marker::Send 允许跨线程转移所有权 Send 标记特性用于标识实现该特性的类型的所有权可以在线程中间转移,几乎所有 Rust 类型都实现了 Send ,但是也有一些例外如: Rc<T> ,如果克隆后在多个线程中转移所有权可能会多个线程同时增加计数器,可以使用 Arc<T> 替代 如果一个新的类型组合的类型都实现了 Send 那么该类型也自动实现了 Send ,几乎所有原始类型都实现了 Send . std::marker::Sync 允许多个线程同时访问 Sync 标记特性用于标识实现该特性的类型可以在多个线程中引用,任何类型 T 是 Sync 并且 T 的引用 &T 是 Send 则意味着引用可以安全的发送给其他线程。 同 Send 类似,几乎所有原始类型都实现了 Sync ,组合了所有类型都是 Sync 的类型自动实现 Sync 。 以下只能指针没有实现 Sync Rc<T> 同样没有实现 Sync RcCell<T> 和 Cell<T> 自己实现 Sync 和 Send 是不安全的

June 29, 2020 · 1 min · Gray King

Rust 宏

三种宏 自定义 #[derive] 属性行为(attribute-like)宏,Rust 属性宏解析 函数行为(function-like)宏 宏 实现元编程,代码生成代码,必须带入当前命名空间内才能使用(不能使用 mod::sub::macro! 这种方式调用)。 #[macro_export] macro_rules! vec { ( $($x:expr), *) => { // $() 用于捕捉值,$x:expr 匹配 Rust 表达式并绑定到 $x,逗号(,)表明一个逗号可能出现在表达式后面,* 表明表达式匹配一次或多次 { let mut temp_vec = Vec::new(); ${ temp_vec.push($x); }* temp_vec } }; } 调用宏用于从属性生成代码 有点像编译期的装饰器: use proc_macro; #[some_attribute] pub fn some_name(input: TokenStream) -> TokenStream { // --snip-- }

June 29, 2020 · 1 min · Gray King

智能指针

智能指针 表现的像一个指针,拥有数据并允许在对数据进行维护。 通常通过 struct 实现并实现两个特性 Deref 和 Drop Deref 允许智能指针实例行为像一个引用,让代码可以同时处理引用和智能指针 Drop 允许自定义智能指针超出作用域的行为。 标准库常见的智能指针 Box<T> 用于在堆分配值 Rc<T> 引用计数类型,允许多个拥有者 Ref<T> 和 RefMut<T> 和通过 RefCell<T> 访问,运行时取代编译期强制检查借用规则 Box<T> 场景: 编译期未知大小的类型(递归类型(自己包含自己类型的类型,如链表)编译期无法确定大小) // 递归类型 enum List { Cons(i32, Box<List>), Nil, } fn main() { let b = Box::new(5); println!("b = {}", b); let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))); } 避免大量数据转移所有权时发生拷贝 拥有一个实现特定特性的值(不关心具体类型)的所有权 Deref 用于自定义解引用操作符( * ) 的行为,智能指针通过实现该特性来模拟普通引用的行为。 对比 fn main() { let x = 5; let y = &x; assert_eq!(5, x); assert_eq!(5, *y); // must dereference } 和 ...

June 29, 2020 · 1 min · Gray King

迭代器

迭代器 所有的迭代器都实现了 Iterator 特性: pub trait Iterator { type Item; // 关联类型 fn next(&mut self) -> Option<Self::Item>; // 返回 None 结束循环 }

June 29, 2020 · 1 min · Gray King

生命周期

生命周期 Rust 中的每一个引用都有其生命周期:引用有效的作用域。 大部分情况下生命周期都是隐式和自举的,在无法完成的情况下就需要我们通过生命周期泛型参数帮助编译器进行注解。 生命周期的主要目标是避免悬空指针。 生命周期泛型参数定义各个引用之间(参数和参数、参数和返回值)的关系,并不改变(延长)变量原本的生命周期 &i32 // a reference &'a i32 // a reference with an explicit lifetime &'a mut i32 // a mutable reference with an explicit lifetime 参考以下代码 fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } 以上代码 标注生命周期 'a 函数有两个引用参数,都使用生命周期 'a 表示两个参数的生命周期必须一致(存活的周期一样长) 函数返回一个引用,并且存活的时间和生命周期 'a 一致 以上指定不改变任何传入的引用的生命周期,我们只是要求借用检查器(borrow checker)检查这些约束。 也就是说借用检查器要检查传入的两个引用的生命周期必须一致,返回的引用的存活周期不能超过传入的引用的存活周期 思考 当函数返回一个引用时,返回值的生命周期注解要和参数的其中之一相匹配,否则那么引用就是指向里函数内创建的值(不能返回)。 也就是说返回引用时,引用的声明周期必须和参数(其一)相关。如果想要返回函数内创建的值最好返回一个有所有权的值类型。 结构体生命周期 如果结构体需要持有引用,需要在定义结构体时给每一个引用都加上生命周期注解。 如果结构体声明了生命周期参数,那么 impl 同样也要声明。 struct ImportantExcerpt<'a> { part: &'a str, } impl<'a> ImportantExcerpt<'a> { fn announce_and_return_part(&self, announcement: &str) -> &str { println!("Attention please: {}", announcement); self.part } } 生命周期省略(elision)规则 函数参数的生命周期为输入生命周期 函数返回值的生命周期为输出生命周期 3 个规则用于 fn 和 impl : ...

June 29, 2020 · 1 min · Gray King

闭包

let add_one = | num | { num + 1 }; 由于闭包和当前上下文相关联,所以 Rust 可以进行类型推导,类型注解也就不是必要的,但是依然可以自己添加: let add_one = | num: i32 | { num + 1 }; fn add_one_v1 (x: u32) -> u32 { x + 1 } let add_one_v2 = |x: u32| -> u32 { x + 1 }; let add_one_v3 = |x| { x + 1 }; let add_one_v4 = |x| x + 1 ; 使用 Fn 存储闭包类型 struct Cacher<T> where T: Fn(u32) -> u32 { calculation: T, value: Option<u32>, } impl Cacher<T> where T: Fn(u32) -> u32 { fn new(calculation: T) -> Cacher<T> { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { if let Some(value) = self.value { value } else { let value = (self.calculation)(arg); self.value = Some(value); value } } } 闭包和函数的区别:闭包会捕捉当前环境,但是函数不会。 ...

June 29, 2020 · 1 min · Gray King

Traits

Traits 定义行为在多个类型中共享。 可以定义默认行为在实现者中间共享。 可以用于定义参数的行为,同样可以定义返回值行为,当用 trait 限定返回值类型时,不能同时(if/else)返回多种实现了该 trait 的类型。 pub trait Summary { fn summarize(&self) -> String; } pub struct Article{ pub title: String, } impl Summary for Article { fn summarize(&self) -> String { format!("{}", self.title) } } pub fn notify(item: impl Summary) { println!("{}", item.summarize()); } // trait bound 语法糖版本 pub fn notify<T: Summary>(item: T) { println!("{}", item.summarize()); } 定义参数行为 通过 impl : fn notify(item: impl TraitName) ,用于简单明了的场景,比如一个参数 通过 trait bound : fn notify<T: TraitName> (item: T) ,用于更复杂的场景,比如多个参数用于减少代码 可以通过 + 连接: fn notify(T: TraitName + Display) (item: T) ...

June 29, 2020 · 1 min · Gray King

错误处理

enum Result<T, E> { Ok(T), Err(E), } ? 操作符 对比 use std::io; use std::io::Read; use std::fs::File; fn read_username_from_file() -> Result<String, io::Error> { let f = File::open("hello.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } } 和 use std::io; use std::io::Read; use std::fs::File; fn read_username_from_file() -> Result<String, io::Error> { let mut f = File::open("hello.txt")?; let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) } 和 ...

June 29, 2020 · 1 min · Gray King

if let

let some_u8_value = Some(0u8); // Without `if let` match some_u8_value { Some(3) => println!("three"); - => (), } // With `if let` if let Some(3) = some_u8_value { println!("three"); }

June 29, 2020 · 1 min · Gray King

模块化

包、crate 和模块 Cargo.toml 表示一个包 包含 0 个或 1 个库 crate( src/lib.rs ) 包含 0 个或多个可执行 crate ( src/main.rs src/bin/*.rs ) 可以同时包含以上两种 模块化系统 模块,一种组织代码和控制路径隐私的方法 所有的项(函数,方法,结构体,枚举,模块和常量)默认私有 不允许使用私有的子模块的代码 可以使用父模块和同级模块的代码 路径,一种命名项的方法 use , 一个将路径带到当前作用域的关键字 pub ,一个将项公开的关键字 as ,一个将带到当前作用域项重命名的关键字 super , 一个相当于文件系统里 .. 作用的关键字 * ,通配符用于使用制定路径下的所有项 pub use 用于重新暴露可以访问的模块 模块可以放在一个文件,也可以按照一定规则拆分到不同文件下 使用同一个 use 清理嵌套的 use use std::cmp::Ordering; use std::io; use std::{cmp::Ordering, io}; use std::io; use std::io::Write; use std::{self, Write}; mod sound { pub mod instrument { pub mod woodwind { pub fn clarinet() { super::breathe_in(); } } fn breathe_in() { } } mod voice { } } fn main() { // 绝对路径以 crate 开始,crate 表示根 crate::sound::instrument::woodwind::clarinet(); // 相对路径 sound::instrument::woodwind::clarinet(); } 上面例子 sound 模块并非公开,但是由于 main 和 sound 定义在同一模块下,所以允许在 main 中引用 sound 。 ...

June 29, 2020 · 1 min · Gray King

模式匹配

#[derive(Debug)] enum UsState { Alabama, Alaska, } enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn value_cents(coin: Coin) -> u8 { match coin { Coin::Peny => { println!("Lucy penny!"); 1 }, Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter(state) => { println!("State quarter from {:?}!", state); 25 }, } } // Option fn plus_one(x: Option<i32>) -> Option<i32> { match x { None => None, Some(i) => Some(i + 1), } } let five = Some(5); let six = plus_one(five); let none = plus_one(None); 编译器会检查 match 覆盖所有情况, _ 可以用于所有未覆盖的情况。

June 29, 2020 · 1 min · Gray King

枚举

多种类型的集合体,一个类型的变量可以存储多种类型的值,枚举的每一项都是该枚举类型的变体: enum IpAddrKind { V4, V6, } fn main() { route(IpAddrKind::V4); route(IpAddrkind::V6); } fn route(kind: IpAddrKind) { // ... } 枚举的每一个变体都可以直接包含数据,并且每一个变体可以包含不同的数据类型和不同的数量,甚至可以直接放结构体(也可以是匿名的)。 struct Ipv4Addr { // --snip-- } enum IpAddr { V4(Ipv4Addr), V6(String), } let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1")); struct Message { Quit, Move{ x: i32, y: i32 }, // anonymous struct Write(String), ChangeColor(i32, i32, i32), // three i32 values } 枚举也可以通过 impl 实现方法 impl Message { fn call(&self) { match self { // ... } } } let m = Message::Write(String::from("hello")); m.call(); Option ...

June 29, 2020 · 1 min · Gray King

结构体

结构体 元组结构体(tuple struct) 用于命名元组并和其他元组进行区分: struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0); 由于定义了元组结构体所有 black 和 origin 是两个不同的类型。 没有字段的结构体:类单元(Unit-Like)结构体 没有任何字段的结构体和单元类型 () 类似,用于实现一些特性(trait)但是没有任何数据。 方法语法 self 占有所有权 &self 不可变借用 &mut self 可变借用 自动引用和解引用 在 Rust 中进行方法调用,如 object.something ,Rust 会自动添加 & &mut 或者 * , 用以自动匹配方法签名。以下是等价的: p1.distance(&p2); (&p1).distance(&p2); 方法如果不声明 self 行参则是一个关联方法(静态方法),通过 :: 调用 struct Rectangle { width: u32, height: u32, } impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle{ width: size, height: size } } } let r = Rectangle::square(10); 每一个结构体可以有多个 impl 块。

June 29, 2020 · 1 min · Gray King

引用和借用

类型前置 & 表示引用,引用允许变量指向一个值但是不发生所有权转移。 引用不占有所有权,所以变量超出作用域之后不会触发 drop 调用。 引用作为函数形参被成为借用(borrowing) 可变引用 针对特定作用域下的特定数据只能创建一个可变引用。如果要创建多个可变引用可以通过大括号创建新的作用域 let mut s = String::from("hello"); { let s1 = mut &s; } let s2 = mut &s; 当已经存在不可变引用时,则无法再创建可变引用,下面代码无法编译通过 let mut s = String::from("hello"); let s1 = &s; // OK let s2 = &s; // OK let s3 = mut &s; // BIG PROBLEM 悬空引用 以下代码是不允许的,无法编译通过 fn main() { let s = dangling_string(); } fn dangling_string() -> &String { let s = String::from("hello"); &s } 上面代码 s 在函数内部分配,那么在函数执行完成后 s 将被释放,所以返回 s 的引用会造成悬空引用。 引用的规则 任何时间针对一个变量,只能有多个不可变引用或者一个可变引用 引用必须一直有效(生命周期) 分片 分片数据类型没有所有权。分片引用一片连续的序列的集合。 字符串分片 字符串分片是一个引用指向 String 的一部分。 let s = String::from("Hello world!") let hello = &s[0..5]; let world = &s[6..11]; 字符串字面量(&str)是个指向二进制程序一块区域的字符串分片,所以函数声明字符串参数使用 &str 会更通用: ...

June 29, 2020 · 1 min · Gray King

所有权

规则 每个值都有一个变量叫做所有者(owner) 同一时间只能有一个所有者 当所有者超出作用域则值被销毁 变量作用域 作用域是一个变量有效的范围 当变量超出作用域范围自动调用对象的 drop 方法进行内存归还操作 变量相互作用:所有权转移(Move) 对于所有在栈上分配的值(固定大小),在进行赋值操作时都对值进行拷贝: let x = 5; ley y = x; // copy 5 to y 但是对于在堆上分配的,变量保存的是指向内存的指针,所以在赋值时拷贝的也是指向该内存的指针: let s1 = String::from("hello"); let s2 = s1; 为了保证内存安全,防止 s1 和 s2 超出作用域范围调用两次 drop 造成重复的内存回收,Rust 会让 s1 不再有效,来避免对 s1 进行回收。继续使用 s1 会导致编译错误。这种情况叫做所有权转移(move)。 变量相互作用:克隆(Clone) 克隆用于深度拷贝变量: let s1 = String::from("hello"); let s2 = s1.clone(); println!(s1); 变量项目作用:拷贝(Copy) 如果数据类型的大小在编译期能够确定都将存储在栈上,这种情况下能够进行快速的拷贝。 Copy 特性(trait)注解用于将值存贮在栈栈上 Copy 特性注解不能和 Drop 特性注解混用 Copy 特性注解使用规则如下 所有的数字类型 所有的布尔型 所有的浮点型 字符类型 所有元素都实现了 Copy 特性注解的元祖 所有权和函数 函数传递实参的规则和变量类似,传递变量到一个函数将为发生所有权转移或者拷贝。 返回值和作用域 返回值可以转移所有权 将一个值赋给其他变量会产生所有权转移 一个包含堆分配的变量超出作用域将会被 drop 清理,除非所有权被转移到其他变量。

June 29, 2020 · 1 min · Gray King

语句和表达式

Rust 区分语句和表达式, Rust 是基于表达式的语言: 语句:执行动作并且不返回值 使用 let 声明变量是语句,所以 let 语句不返回值,也就不能像 Python 那样将 let 语句赋值给其他变量 函数声明也是语句 表达式:计算并返回值,不以分号(;)结尾 5 + 6 是一个表达式,计算并返回值 11 表达式可以作为语句的一部分 函数调用是表达式 宏调用是表达式 用 {} 创建的块也是表达式 let x = { let y = 6; y + 5 } if loop while for 是表达式 在表达式后面增加分号(;)可以将一个表达式转为语句。

June 29, 2020 · 1 min · Gray King

Member initialize

tags: C/C++ 如果类成员属性是值类型或者引用类型则需要改对象有无参数构造方法,否则类无法实例化, 这是因为这类成员属性在构造函数调用之前就需要进行初始化。 下面代码无法通过编译 class Foo { public: Foo(int n) : n {n} { }; ~Foo() { }; private: int n; }; class Bar { public: Bar(int n) { this->foo = Foo(n); }; ~Bar(); private: Foo & foo; };

June 28, 2020 · 1 min · Gray King

Iterator class

tags: C/C++ 容器类实现 begin 和 end 方法返回 Iterator class 的实例, Iterator class 通过实现友元类可以直接访问容器类的私有属性, Iterator class 通过重载 ++/==/* 等操作符实现对容器类的访问并通过自己的私有属性记录当前位置。 Iterator class 重载的操作符: ++ 移动容器元素位置 == 判断两个容器位置是否相等(容器是否一个,位置是否一个) * 解引用返回当前位置指向的容器的值

June 28, 2020 · 1 min · Gray King

SSE/AVX/AVX2/AVX512

tags: Computer Systems,C/C++,优化,High Performance 部分 intel CPU 支持向量指令集同时进行多路整数和浮点数计算,以此来进行对相关算法进行优化,这里整理相关链接: 编译器支持相关封装避免编写汇编代码,官方指南:Intrinsics Guide 基于 sse_mathfun 的 avx_mathfun 封装相关宏和函数 mp3 库 lame 中的 SSE 加速实现 libmp3lame/vector/xmm_quantize_sub.c AVX512 VNNI https://en.wikichip.org/wiki/x86/avx512_vnni

June 28, 2020 · 1 min · Gray King

优化

AVX512

June 28, 2020 · 1 min · Gray King

CMake

tags: C/C++,Programming Tools 安装的头文件必须包含在目标的源代码中,否则构建如 iOS 的 Framework 时无法正确包含头文件 ADD_LIBRARY(test test.h) CMake 生成 C++ LSP 配置文件

June 28, 2020 · 1 min · Gray King

Build System

CMake

June 28, 2020 · 1 min · Gray King

Emacs Tmux 256 colors

tags: Emacs 生成 terminfo $ cat <<EOF > terminfo-24bits.src # Use semicolon separators. xterm-24bits|xterm with 24-bit direct color mode, use=xterm-256color, Tc, setb24=\E[48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm, setf24=\E[38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm,]] EOF $ tic -x -o ~/.terminfo terminfo-24bits.src 通过 xterm-24bits 启动 Emacs $ env TERM=xterm-24bits emacs Emacs 通过 list-color-display 查看效果。

June 3, 2020 · 1 min · Gray King

Rust Trait Object

tags: Rust 动态大小类型(DST)和 Sized 特性 str (非 &str )就是一个 DST,我们不能在运行时得知 str 的大小。 &str 是一个指针类型,大小是已知的。 DST:拥有额外的元数据存储动态大小的信息。 每一个特性都是一个是个 DST,使用 Trait Object 必须是像 &dyn Trait 和 Box<dyn Trait> (或 Rc<dyn Trait> )的指针类型。 dyn 关键字 dyn 关键字用于将 Trait Object 指针和普通的结构体指针区分开来。 Sized vs ?Sized Rust 有一个特定的特性叫做 Sized 去判断一个类型的大小是否是编译期可知的,并且自动在编译期为所有已知大小的类型实现, 同时 Rust 隐式的为泛型函数的类型参数加上 Sized 的限制(bound),下面这样的泛型函数: fn generic<T>(t: T) { // --snip-- } 实际上相当于像下面这样硬编码: fn generic<T: Sized>(t: T) { // --snip-- } 也可以通过下面特定的语法取消这个限制: fn geneic<T: ?Sized>(t: &T) { // --snip-- }

March 29, 2020 · 1 min · Gray King

Rust Wrapper Types

tags: Rust

March 25, 2020 · 1 min · Gray King

《架构整洁之道》读书笔记

tags: 读书笔记,系统架构 第一遍粗读 三个编程范式:结构化编程、面向对象编程、函数式编程 每个编程范式都是增加限制: 结构化编程限制了 goto 面向对象编程限制了函数指针 函数式编程限制可变变量(变量不可修改) 设计原则:SOLID

March 23, 2020 · 1 min · Gray King

SOLID

SRP: Single Responsibility Principle 浅显的解释是软件模块只提供单一功能 更进一步任何一个软件模块都应该有且只有一个被修改的原因 再更进一步这个原则是关于人(Actor)的 任何一个软件模块都应该只对一个用户或系统利益相关者负责。 最终就是任何一个软件模块都应该只对某一类行为负责 OCP:Open/Closed Principle 设计良好的软件应该易于扩展,同时抗拒修改。也就是说一个软件模块应该允许在不修改源码的情况下扩展它的行为。 可以通过组合 SRP(代码分组)和调整依赖关系实现(DIP)。如果 A 组件不想被 B 组件上发生的修改所影响,那么就应该让 B 组件依赖于 A 组件。 LSP:Liskov Substitution Principle 里氏替换原则:多态。 每个类型是 S 的对象 o1 都存在一个类型为 T 的对象 o2,能使操作 T 类型的程序 P 在用 o2 替换 o1 时行为保持不变,我们就可以将 S 称为 T 的子类型。 public class LiskovSub { public static main(String[] args) { T o1 = new S(); T o2 = new T(); P(o1); // ok P(o2); // ok } public static P(T o) { o.doSomeThing(); } } 正长方形问题 ...

March 23, 2020 · 1 min · Gray King