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

系统架构

tags: 技术 设计原则 SOLID 好的架构 我认为好的架构 能够无心智障碍的编写运行单元测试 从一起作业看好的架构 应该能够让任何开发人员方便的随时上线和回滚 面对上线对基础设施没有心理压力 完备的监控

March 22, 2020 · 1 min · Gray King

《百箭穿杨》读书笔记

需要熟悉股市相关概念进行扫盲。 粗读要点 树立安全边际,跟随格雷厄姆 寻找好的困难股,降低触底难度,加大触底区间,预测底部区间,分 5 档抄底,最好在 1-3 档就能完成抄底 每次只买总资产的 1% 盈利后可以将本金提出,只留底仓等待顶峰信号后抛出赚取高额利润的前提下保障本金 总是留 25%-40% 的现金 做长线 分析财报看毛利、营收增长率、负债率可以确定一个好股,然后就等一些情况下这只股遇到困难触底 看行业处于哪个周期:萌发、成长啥的 不做重仓 复读要点完善 安全边际 跟随格雷厄姆 偏离:更保守或更激进 大赚小赔不如小赚不赔:不亏钱 困境好企 做有把握的事,不啃硬骨头,广撒网,多捞鱼,选取一批困境好企来实现从小盘大稳定增长股 行业中的好企业标准 行业很关键 需求无限,供给有限 关注行业周期 大周期:新生->成长->成熟->衰落->消亡 小周期:大周期各个过程中的景气与萧条(一两年、三五年甚至一二十年) 消亡之前会有死灰复燃,大周期中成长阶段会有萧条,注意区分。 门槛高,竞争少 只有少数寡头,估值会高 唯一或第一 成熟行业比较简单,成长行业比较困难。 通过企业原则、经营原则、财务原则和市场原则衡量。- P28 生活经验活常识也很重要。 落难好企 行业顺境,某些原因导致的猜疑导致股价下跌 行业遭遇整体困境:偶然事件,反转时间比好把握 个股困境,主打产品破灭:有无法度过的风险 财务数据衡量困境好企能否度过难关 - P32 负债率越低越好:不能超过 50% 资产中的现金越多越好:高于股东权益的 1/3,刚上市的好过上市很久的老企业(把钱折腾光了) 产品的毛利率越高越好:市场有需求 应收账款越少越好:钱可能收不回来 通过季报发现反转时机 季报时间长,抗短期干扰,一季度定调、二季度(半年)纠偏或修正、三季度出结果(更好或更差)、四季度(年报)成果汇报和新的起点用于比较第一季度。 一季度和半年狠重要。 通过 营业收入 发现转机。困境表现为净利润增速下滑,之前是好企可能会市盈率过高。 容错寻底 不亏钱的情况下寻找极限底部,保障安全、带来最大利润、带来良好心态 变种“不破买价”:买入的价格很难再跌回原来的位置 变成左侧交易者,不追涨 大盘底与个股底的关系 同步性:大盘筑底个股也在筑底,大盘达到最低位时,个股也先后到达最低位 差异性 大盘下跌蓝筹股先跌到位,大盘下跌过程中小盘成长股与稳定增长股少许跟跌或逆市上扬。 市场反弹小盘成长股与稳定增长股开始杀跌。 耦合性:大盘底出现时次新股出现底部的概率大,老股形成底部可能需要好几年 – P56 ...

March 20, 2020 · 1 min · Gray King

Kafka

tags: Bigdata 相关知识点 概念组成 Producer 消息产生者,往指定 Topic 的指定 Partition 发送消息 Consumer Group 消费指定 Topic 的消息 Consumer 消费指定 Topic 下某一分区的消息 Topic 区分不同消息主题 Partition 保证同一分区的有序性 Connector 消息可被不同的 Consumer Group 重复消费(广播或订阅)。同一 Consumer Group 下的不同 Consumer 分别消费不同的 Partition,Consumer 数量不能超过 Partition 数量。 数据被持久化并分片成功后发送 ACK 保证里数据不被丢失。 设计 持久化 基于文件系统 基于队列是顺序的和磁盘的顺序访问要比内存的随机访问要快(参见 The Pathologies of Big Data), Kafka 采用在磁盘文件系统上尾部写头部读的方式。 Kafka 没有采用 BTree 存储数据因为 BTree 的操作是 O(log N) ,而且对磁盘的 seek 操作要慢,且同时只能进行一次限制了并行,所以实际操作比 O(log N) 要慢 基于磁盘的顺序访问进行在尾部写和头部读,可以实现读写都是 O(1) 的时间复杂度,并且读写互不干扰 基于以上实现,Kafka 可以不必在消息一经消费就删除,而是可以保留消息一段相对较长的时间(比如一周) 高效 并且采用统一的日志格式,可以方便的使用 sendfile 避免字节拷贝以在各个组件之间高效的交换日志文件 ...

March 20, 2020 · 1 min · Gray King

LeetCode

tags: Learning,Algorithm

March 20, 2020 · 1 min · Gray King

LeetCode: Trapping Tain Water

tags: LeetCode

March 20, 2020 · 1 min · Gray King

Linux Virtual Memory Management

tags: Linux 原文连接:Linux Virtual Memory Management Chapter 2 Describing Physical Memory:描述物理内存 独立于平台架构的方式描述内存 — 更好的支持多平台 本章包含描述存储器、内存页的结构体(structures)和一些影响 VM 行为的标识位(flags) VM 中普遍(prevlent)认为第一重要(principal)的概念是 NUMA。 大型机器中内存访问速度取决于 CPU 到内存的距离。比如一组(bank)内存分配给每一个处理器或者一组内存非常适合靠近的 DMA 设备卡。 这里的每组(bank)内存被称为节点(node)并且这个概念在 Linux 中通过 struct pglist_data(typedef pg_data_t) 表示,即使在 UMA 架构下也是如此。每一个节点是一个由 NULL 结尾的链表,通过 pg_data_t->next_node 指向下一个节点。 每一个节点都被分割成多个块(block)称为分区(zone)用于表示内存中的范围。分区使用 struct zone_struct(typedef zone_t) 结构体描述,每一个分区都是以下三种类型的一种 ZONE_DMA 开始 16MB 内存,供 ISA 设备使用 ZONE_NORMAL 16MB - 896MB,由内核直接映射到线性地址空间的上部区域(将在第四章讨论) ZONE_HIGHMEM 896MB - END,剩余不由内核直接映射的系统可用内存, 大部分内核操作都只能使用这种类型的分区,所以这里也是这里也是最关键的性能区域(most performance critical zone) 每一个物理页帧(physical page frame)都使用结构体 struct page 表示,所有的结构体都保存在全局数组 mem_map 中,mem_map 通常存储在 ZONE_NORMAL 的开始处; 结构体之间的关系 内存节点 Linux 在分配内存页的时候采用 本地节点分配策略(node-local allocation policy) 通过最靠近当前运行 CPU 的节点去分配内存。同时进程也会趋向于采用同一 CPU 运行。 ...

March 20, 2020 · 4 min · Gray King

动态规划

tags: Algorithm 状态转移方程 无后效性 如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响。 一旦 \(f(n)\) 确定,“我们如何凑出 \(f(n)\) ”就再也用不着了: 要求出 \(f(15)\),只需要知道 \(f(14)\),\(f(10)\),\(f(4)\) 的值, 而 \(f(14)\),\(f(10)\),\(f(4)\) 是如何算出来的,对之后的问题没有影响。 “未来与过去无关”,这就是无后效性。 最优子结构 大问题的最优解可以由小问题的最优解推出,这个性质叫做“最优子结构性质”: \(f(n)\) 的定义需要蕴含“最优”,利用 \(f(14)\),\(f(10)\),\(f(4)\) 的最优解,我们即可算出 \(f(15)\) 的最优解。 能将大问题拆成几个小问题,且满足无后效性、最优子结构性质。 DP 思路 参见 LeetCode 讨论: 先写出穷举的方法 找出不必要的重复计算 写出 DP 练习 0x00 硬币找零 描述 假设有几种硬币,如1、3、5,并且数量无限。请找出能够组成某个数目的找零所使用最少的硬币数。 状态转移公式 公式 \(f(n)=min\{f(n-1),f(n-3),f(n-5)\} + 1\) 检查是否满足上面提到的两个特性: 无后效性:对于 \(n\),一旦 \(f(n)\) 确定,以后只关心 \(f(n)\) 的值,不关心怎么计算的; 最优子结构:对于 \(n\),只要 \(n - 1\) \(n - 3\) \(n - 5\) 能是最优解,那么就能计算出 n; 推导过程 假设找零 15: 若优先使用 5 元硬币 \(cost = f(10) + 1 = 2 + 1 = 3\) ...

March 20, 2020 · 2 min · Gray King

归并排序

tags: Algorithm,Sorting Wikipedia: 归并排序

March 20, 2020 · 1 min · Gray King

算法

alias: Algorithm

March 20, 2020 · 1 min · Gray King

Let's Encrypt

tags: Over the Wall,HTTPs 这里以新增 vd.linuxzen.com 为例。 新增 DNS 解析 通过 DNSPOD 新增 DNS 解析 A 记录 调整 Nginx 新增 HTTP 站点 Nginx 参考配置 server { listen 80; server_name vd.linuxzen.com; include /etc/nginx/snippets/letsencrypt-acme-challenge.conf; } 新增签发证书 $ acme.sh --force --issue -d linuxzen.com -d www.linuxzen.com -d cwiki.linuxzen.com -d monitor.linuxzen.com -d v.linuxzen.com -d vd.linuxzen.com -d d.linuxzen.com -d piwik.linuxzen.com -d t.linuxzen.com -d wiki.linuxzen.com -d note.linuxzen.com -w /var/www/letsencrypt/ 安装证书 $ acme.sh --install-cert -d linuxzen.com --cert-file /etc/nginx/certs/linuxzen.com/cert.pem --key-file /etc/nginx/certs/linuxzen.com/privkey.pem --fullchain-file /etc/nginx/certs/linuxzen.com/fullchain.pem --reloadcmd "sudo service nginx reload && docker restart ipsec-vpn-ssl && docker restart v2ray && docker restart v2ray2" 调整 Nginx 配置文件应用证书 server { listen 80; server_name vd.linuxzen.com; return 301 https://$server_name$request_uri; } server { listen 443 http2 ssl fastopen=3 reuseport; server_name vd.linuxzen.com; ssl_certificate /etc/nginx/certs/linuxzen.com/fullchain.pem; ssl_certificate_key /etc/nginx/certs/linuxzen.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security max-age=15768000; access_log /var/log/nginx/vd.linuxzen.com.log; location / { root /srv/www/vd.linuxzen.com; index index.html index.htm; } location /passport { proxy_redirect off; proxy_pass http://v2ray; proxy_http_version 1.1; proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } include /etc/nginx/snippets/letsencrypt-acme-challenge.conf; }

March 19, 2020 · 1 min · Gray King

Over the Wall

March 19, 2020 · 0 min · Gray King

V2Ray

tags: Over the Wall,Tools 架构 Client -> DIDIYun(HAProxy) -> HK 滴滴云 HAPorxy 配置 117.51.146.119 frontend v_linuxzen_com bind *:6697 option tcplog mode tcp default_backend v_linuxzen_com_nodes backend v_linuxzen_com_nodes mode tcp balance roundrobin option ssl-hello-chk server webserver1 45.115.36.35:443 check 客户端改动 需要调整 hosts $ echo '117.51.146.119 v.linuxzen.com' | sudo tee -a /etc/hosts HK V2Ray Docker 启动 $ docker run -d -p 127.0.0.1:25001:25001 --name v2ray --restart always -v /etc/v2ray:/etc/v2ray v2ray/official HK Let’s Encrypt 证书 $ acme.sh --issue -d linuxzen.com -d www.linuxzen.com -d cwiki.linuxzen.com -d monitor.linuxzen.com -d v.linuxzen.com -d d.linuxzen.com -d piwik.linuxzen.com -d t.linuxzen.com -d wiki.linuxzen.com -d note.linuxzen.com -w /var/www/letsencrypt/ $ acme.sh --install-cert -d linuxzen.com --cert-file /etc/nginx/certs/linuxzen.com/cert.pem --key-file /etc/nginx/certs/linuxzen.com/privkey.pem --fullchain-file /etc/nginx/certs/linuxzen.com/fullchain.pem --reloadcmd "sudo service nginx reload && docker restart ipsec-vpn-ssl && docker restart v2ray && docker restart v2ray2" HK V2Ray 配置 { "log": { "loglevel": "debug", "access": "/var/log/v2ray/access.log", "error": "/var/log/v2ray/error.log" }, "inbounds": [ { "port": 25001, "listen":"0.0.0.0", "protocol": "vmess", "settings": { "clients": [ { "id": "1fde12b8-0cfd-11ea-a4b3-acde48001122", "alterId": 64 } ] }, "streamSettings": { "network": "ws", "wsSettings": { "path": "/passport" } } } ], "outbounds": [ { "protocol": "freedom", "settings": {} } ] } HK Nginx 配置 server { listen 80; server_name v.linuxzen.com; return 301 https://$server_name$request_uri; } upstream v2ray { server 127.0.0.1:25001; server 127.0.0.1:25002; } server{ listen 443 http2 ssl fastopen=3 reuseport; # listen 80; server_name v.linuxzen.com; ssl_certificate /etc/nginx/certs/linuxzen.com/fullchain.pem; ssl_certificate_key /etc/nginx/certs/linuxzen.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security max-age=15768000; access_log /var/log/nginx/v.linuxzen.com.log; location / { root /srv/www/v.linuxzen.com; index index.html index.htm; } location /passport { proxy_redirect off; proxy_pass http://v2ray; proxy_http_version 1.1; proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } include /etc/nginx/snippets/letsencrypt-acme-challenge.conf; } 新增一个域名用于单独的滴滴云加速 使用一个单独的域名 vd.linuxzen.com 用于滴滴云加速,参见Let’s Encrypt。

March 19, 2020 · 2 min · Gray King

xinetd

tags: Over the Wall,Network xinetd 代理 SMTP 和 IMAP 通过 xinetd 代理 SMTP 和 IMAP 实现 gmail 翻墙。 配置服务端 service imap { type = UNLISTED port = 993 bind = 0.0.0.0 socket_type = stream wait = no user = nobody redirect = imap.gmail.com 993 per_source = UNLIMITED cps = 100 2 } service smtp-465 { type = UNLISTED port = 465 bind = 0.0.0.0 socket_type = stream wait = no user = nobody redirect = smtp.gmail.com 465 per_source = UNLIMITED cps = 100 2 } service smtp-587 { type = UNLISTED port = 587 bind = 0.0.0.0 socket_type = stream wait = no user = nobody redirect = smtp.gmail.com 587 per_source = UNLIMITED cps = 100 2 } 本机修改 hosts ...

March 19, 2020 · 2 min · Gray King

股市相关概念

股分类 个股:投资资金来自个人的股票(还有国家股、法人股) 蓝筹股:明星股 小盘 市值比较低的股票 小盘价值股:格低于价值的股票,被低估的股票,长期看来值得投资的股票。 小盘成长股:成长潜力很大,公司发展处于较快阶段,但不确定性也比较高,业绩波动可能会很大。 稳定增长股:小盘具有一定品牌效应后的快销品,达到一定统治地位,最好在行业的繁荣周期顶峰卖出 周期股 相关指标 市盈率(P/E 或 PER)= 每股市值 / 每股盈余 每股市价处于每股盈余(EPS),评估股价是昂贵还是便宜。市盈率越低代表投资者能够以相对较低的价格购入股票。 Wikipedia: https://zh.wikipedia.org/wiki/%E5%B8%82%E7%9B%88%E7%8E%87 市净率(PBR,P/B) = 总市值 / 净资产 评估高风险企业,企业资产大量为实物资产的企业时收到重视。 市销率(PSR,P/S) = 总市值 / 营收 公司市值除以上一财年(或季度)的营业收入,或等价地,以公司股价除以每股营利收入,越小(小于 1)通常被认为投资价值越高。可以付出比单位营收更少的钱购买股票。 Wikipedia: https://zh.wikipedia.org/zh-hans/%E5%B8%82%E9%94%80%E7%8E%87 相关链接 简单直观的解释一下市盈率和市净率的意思

March 18, 2020 · 1 min · Gray King

基金定投

适合人群:穷人、笨人、忙人、好人 为什么 通胀太高,股票战胜通胀的重要工具 绝大多数人不具备择时能力 避免高点买入 核心逻辑:放弃择时,持续小额买入,降低成本 缺点:在市场上涨、高位震荡过程中,虽然盈利大幅提高,但持仓成本也在快速提高。一旦市场转向熊市,整体会迅速亏本。 单边上涨:定投盈利少于一次性投资 先震荡后上涨:定投盈利少于一次性投资 先上涨后下跌:定投亏损多于一次性投资 单边下跌:定投亏损少于一次性投资 震荡:定投与一次性投资持平 先下跌再震荡:定投亏损少于一次性投资 除了坚持,还在于止盈策略,牛市中成本不断提高,需要及时止盈,防止下跌时候的亏损 错误理念 定投不是万能,需要防止“倒微笑曲线周期” 巴菲特说指数基金难以超越仅限于美股,A 股与之相反 定投组合包含债券基金:定投适合波动较大的权益类资产(股票、商品),债卷等固定收益类产品本身波动小,一次性买入和定投基本没区别 月定投不够还要周定投:基本没差别 定投是懒人投资,坚持即可:还需要主动管理,如定投的标的不再适合定投,该换要换。 一次性投资止损不止赢,定投止赢不止损。 定投只买开放式基金:还可以宽基指数基金、主题指数基金、行业指数基金、风格指数基金、策略指数基金、QDII 指数基金、商品指数基金。此外,还有折价的封闭式基金、定增基金,适当的配置会非常好玩。 策略 定投买入,止盈不止损: 需要在可能出现的“倒微笑曲线周期”及时止盈。 制订量化估值标准 技术分析 通过MA、MACD、RSI等各种技术指标,判断目前市场从长期看,是相对低位还是高位 趋势上涨原则:MA(30)>MA(60)>MA(120); 趋势下跌原则:MA(30)<MA(60)<MA(120)。 均线偏离法:根据指数价格对均线偏离的程度决定投资额度的多少。 P>MA(120):正偏离,减少投资额度; P<MA(120):负偏离,增加投资额度。 基本面分析 根据指数相关基本面指标,判断股市处于高估或者低估。如市盈率、市净率、整体ROI等地。在股市高估时,降低投资额度,在股市低估时,增加投资额度。 定期不定额策略 在上述策略的基础上,如目前市场明显在历史地点,原来每个月投1000的,这时不妨投2000。如市场明显高估,每个月投1000的可以投500。如果涨的都害怕了,可以不投甚至卖出一部分。 产品池管理 构建“核心——卫星”组合 技巧 部分基金可以场内购买(炒股账号购买),交易时间短手续费低 Links 基金定投,看这篇就够了

March 11, 2020 · 1 min · Gray King

Deep Learning

tags: AI What is the Difference Between CNN and RNN?

March 10, 2020 · 1 min · Gray King

AI

Machine Learning Deep Learning 《机器学习实战》读书笔记 How to Train Really Large Models on Many GPUs?

March 9, 2020 · 1 min · Gray King

《巴比伦富翁新解》读书笔记

积累财富首先要改变思维,学习复利的力量。 粗读要点 实践 10/50 懒人储蓄投资自己,工资 10% 奖金 50% 存储单独的账户用户投资自己 开辟单独基金用于存放房租、孩子学费和自我投资 不懂不投,宁愿错过,不犯过错 画出自己的财富水池 为自己购买保险规避风险(大病和死亡),完成家庭保险配置 理清房贷还款计划,怎么将还款金额降低到收入到 1/3 (9000)以下,可以考虑先提前还房贷减轻房贷利息压力

March 7, 2020 · 1 min · Gray King

CPI

反映与居民生活有关的产品及劳务价格统计出来的物价变动指标,衡量通货膨胀的主要指标之一: 超过 3% 为通货膨胀 超过 5% 就是比较严重的通货膨胀 Links 消费者物价指数

March 7, 2020 · 1 min · Gray King

ELisp

tags: Emacs 'foo vs #'foo https://emacs.stackexchange.com/a/10943 #’ on symbols will cause the byte-compiler to emit a warning if the function is not defined.

March 7, 2020 · 1 min · Gray King