diff --git a/source/_posts/ASP.NET Core.md b/source/_posts/ASP.NET Core.md index 3d42f4a..77000d4 100644 --- a/source/_posts/ASP.NET Core.md +++ b/source/_posts/ASP.NET Core.md @@ -4,6 +4,53 @@ date: 2021-03-23 10:30:31 author: 文永达 top_img: https://gcore.jsdelivr.net/gh/volantis-x/cdn-wallpaper/abstract/67239FBB-E15D-4F4F-8EE8-0F1C9F3C4E7C.jpeg --- +# IDE智能提示优化 + +## .Net6 的汉化 + +### 本地化xml生成工具 + +工具以`dotnet cli`发布,使用`dotnet tool`进行安装 + +```shell +dotnet tool install -g islocalizer +``` + +`.net6`的汉化包已经有现成的了,可以直接进行安装 + +```shell +islocalizer install auto -m net6.0 -l zh-cn +``` + +工具会自动从`github`下载对应的包进行安装(可能需要访问加速)。 +也可以通过`-cc`参数指定内容对照类型 + +- `OriginFirst`: 原始内容在前 +- `LocaleFirst`: 本地化内容在前 +- `None`: 没有对照 + +```shell +islocalizer install auto -m net6.0 -l zh-cn -cc OriginFirst +``` + +自定义生成 + +如下示例生成`.net6`的原始内容在前的`zh-cn`本地化包,并使用 `---------` 分隔原文和本地化内容,生成完成后的`包路径`会输出到控制台。 + +可以通过 `islocalizer build -h` 查看更多的构建参数信息。 + +首次构建过程可能非常缓慢(需要爬取所有的页面),相关文件会被缓存(单zh-cn内容大小约3.5G),再次构建时会比较快; + +安装 + +```shell +islocalizer install {包路径} +``` + +`包路径`为build命令完成后输出的路径。 + +可以通过 `islocalizer -h` 查看更多的命令帮助。 + # Web API 项目初始化搭建 首先打开Visual Studio 2022,然后选择创建新项目 diff --git a/source/_posts/Rust.md b/source/_posts/Rust.md index 89f0187..355887c 100644 --- a/source/_posts/Rust.md +++ b/source/_posts/Rust.md @@ -99,6 +99,32 @@ cargo run 系统在创建工程时会生成一个Hello World源程序main.rs,这时会被编译运行: +# Rust 标准库中文版 + +该仓库包含 `rust-src` 组件的所有源代码文件,并对其所有的源代码进行翻译,主要包括对 Rust 核心库的翻译,Rust 标准库的翻译,以及其他一些资源。该仓库使用 [`Cmtor`](https://gitee.com/dirname/rust-library-chinese/tree/main#) (我写的效率工具) 程序并借助 `JSON` 文件来完成翻译的所有工作,当 Rust 更新时,将尽可能为其生成中文翻译。 + +## 下载翻译好的 Rust 文档 + +每次在构建新的中文文档时,会修复之前构建结果中存在的问题,为了尽可能的保证翻译的准确性,本仓库只提供最新版本的构建。最新的构建结果会放在 [`dist`](https://gitee.com/dirname/rust-library-chinese/blob/main/dist) 目录下,您可以手动跳转到该文件夹,下载最新的构建结果 + +## 使用 Rust 中文文档 + +> - 在使用中文文档时,请注意版本号,中文文档版本和 Rust 版本号必须要保持一致。 +> - 必须使用 `stable` 版本,不要使用 `beta` 和 `nightly` 版本。 +> - 在翻译后的源代码中,一些文档的底部会存在一定量的内容为空的注释行,其实这是有意为之,请不要擅自修改和删除。如果您删除了它,就会导致 `source-map` 失效,当 `source-map` 失效后,在调试源代码时就会出现执行位置和源代码位置不一致的严重问题。 + +请确保 Rust 已经安装好,并且可以正常工作。在 Rust 安装成功后,您还应该通过 `rustup component add rust-src` 命令来安装 `rust-src` 组件。当安装 `rust-src` 组件之后,请按照以下步骤进行操作: + +1. 在终端执行: `rustup default stable` 来切换到 `stable` 版本,并确保 `stable` 的版本与中文版文档所对应的版本一致 +2. 在终端执行 `rustup show`,然后在输出中找到 `rustup home` 所对应的路径,然后将其在资源管理器中打开 +3. 打开 `toolchains` 的文件夹,在该文件夹下,找到您当前所使用的 Rust 工具链并将其打开,例如,在 `Windows` 平台上对应的是 `stable-x86_64-pc-windows-msvc` 文件夹 +4. 然后打开 `lib/rustlib/src/rust` 目录,这个目录下的文件夹就是 Rust 标准库源代码所在的位置 +5. 将 `lib/rustlib/src/rust/library` 文件夹下的所有内容保存一份副本,然后删除 +6. 下载本仓库对应的中文文档源文件,`dist`目录下`zip`压缩包将其解压缩并将其下的 `library` 并放置到 `lib/rustlib/src/rust` 文件夹下 +7. 请确保您已经在 IDE 中安装 Rust 相关插件,例如,`vscode` 需要安装:[rust-analyzer](https://gitee.com/link?target=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dmatklad.rust-analyzer) +8. 重新启动 `IDE` 工具,中文文档的智能提示开始工作 +9. 愉快的编码! + # Cargo 教程 ## Cargo 是什么 @@ -256,3 +282,341 @@ let a = 123; // 可以编译,但可能有警告,因为该变量没有被 let a = 456; ``` +但是如果 a 是常量就不合法: + +```rust +const a: i32 = 123; +let a = 456; +``` + +变量的值可以"重新绑定",但在"重新绑定"以前不能私自被改变,这样可以确保在每一次"绑定"之后的区域里编辑器可以充分的推理程序逻辑。虽然 Rust 有自动判断类型的功能,但有些情况下声明类型更加方便: + +```rust +let a: u64 = 123; +``` + +这里声明了 a 为无符号 64 位整型变量,如果没有声明类型,a 将自动被判断为有符号 32 位整型变量,这对于 a 的取值范围有很大的影响。 + +## 重影 (Shadowing) + +重影的概念与其他面向对象语言里的"重写"(Override)或"重载"(Overload)是不一样的。重影就是刚才讲述的所谓"重新绑定",之所以加引号就是为了在没有介绍这个概念的时候代替一下概念。 + +重影就是指变量的名称可以被重新使用的机制: + +```rust +fn main() { + let x = 5; + let x = x + 1; + let x = x * 2; + println!("The value of x is: {}", x); +} +``` + +这段程序的运行结果: + +```shell +The value of x is: 12 +``` + +重影与可变变量的赋值不是一个概念,重影是指用同一个名字重新代表另一个变量实体,其类型、可变属性和值都可以变化。但可变变量赋值仅能发生值的变化。 + +```rust +let mut s = "123"; +s = s.len(); +``` + +这段程序会出错:不能给字符串变量赋整型值。 + +# Rust 数据类型 + +Rust 语言中的基础数据类型有以下几种。 + +## 整数型(Integer) + +整数型简称整形,按照比特位长度和有无符号分为以下种类: + +| 位长度 | 有符号 | 无符号 | +| ------- | ------ | ------ | +| 8-bit | i8 | u8 | +| 16-bit | i16 | u16 | +| 32-bit | i32 | u32 | +| 64-bit | i64 | u64 | +| 128-bit | i128 | u128 | +| arch | isize | usize | + +iszie 和 usize 两种整数类型是用来衡量数据大小的,它们的位长度取决于所运行的目标平台,如果是 32 位架构的处理器将使用 32 位位长度整型。 + +整数的表述方法有以下几种: + +| 进制 | 例 | +| -------------------- | ----------- | +| 十进制 | 98_222 | +| 十六进制 | 0xff | +| 八进制 | 0o77 | +| 二进制 | 0b1111_0000 | +| 字节(只能表示 u8 型) | b'A' | + +很显然,有的整数中间存在一个下划线,这种设计可以让人们在输入一个很大的数字时更容易判断数字的值大概是多少。 + +## 浮点整型(Floating-Point) + +Rust 与其他语言一样支持 32 位浮点数(f32)和 64 位浮点数(f64)。默认情况下, 64.0 将表示 64 位浮点数,因为现代计算机处理器对两种浮点数计算的速度几乎相同,但 64 位浮点数精度更高。 + +```rust +fn main() { + let x = 2.0 // f64 + let y: f32 = 3.0; // f32 +} +``` + +## 数学运算 + +用一段程序反映数学运算: + +```rust +fn main() { + let sum = 5 + 10; // 加 + let difference = 95.5 - 4.3; // 减 + let product = 4 * 30; // 乘 + let quotient = 56.7 ? 32.2; // 除 + let remainder = 43 % 5; // 求余 +} +``` + +许多运算符号之后加上 = 号是自运算的意思,例如: + +`sum + 1` 等同于 `sum = sum + 1`。 + +**注意:**Rust 不支持 **++** 和 **--**,因为这两个运算符出现在变量的前后会影响代码可读性,减弱了开发者对变量改变的意识能力。 + +## 布尔型 + +布尔型用 bool 表示,值只能为 true 和 false。 + +## 字符型 + +字符型用 char 表示。 + +Rust 的 char 类型大小为 4 个字节,代表 Unicode 标量值,这意味着它可以支持中文,日文和韩文字符等非英文字符甚至表情符号和零宽度空格在 Rust 中都是有效的 char 值。 + +Unicode 值的范围从 U+0000 到 U+D7FF 和 U+E000 到 U+10FFFF(包括两端)。但是,"字符"这个概念并不存在与 Unicode 中,因此您对"字符"是什么的直觉可能与Rust中的字符概念不匹配。所以一般推荐使用字符串储存 UTF-8 文字(非英文字符尽可能地出现在字符串中)。 + +**注意:**由于中文文字编码有两种(GBK 和 UTF-8),所以编程中使用中文字符串有可能导致乱码的出现,这时因为源程序与命令行的文字编码不一致,所以在 Rust 中字符串和字符都必须使用 UTF-8 编码,否则编译器会报错。 + +## 复合类型 + +元组是一对`( )`包括的一组数据,可以包含不同种类的数据: + +```rust +let tup: (i32, f64, u8) = (500, 6.4, 1); +// tup.0 等于 500 +// tup.1 等于 6.4 +// tup.2 等于 1 +let (x, y, z) = tup; +// y 等于 6.4 +``` + +数组用一对`[ ]`包括的同类型数据。 + +```rust +let a = [1, 2, 3, 4, 5]; +// a 是一个长度为 5 的整型数组 + +let b = ["January", "February", "March"]; +// b 是一个长度为 3 的字符串数组 + +let c = [i32; 5] = [1, 2, 3, 4, 5]; +// c 是一个长度为 5 的 i32 数组 + +let d = [3; 5]; +// 等同于 let d = [3, 3, 3, 3, 3]; + +let first = a[0]; +let second = a[1]; +// 数组访问 + +a[0] = 123; // 错误:数组 a 不可变 +let mut a = [1, 2, 3]; +a[0] = 4; // 正确 +``` + +# Rust 函数 + +函数在 Rust 语言中是普遍存在的。 + +通过之前的章节已经可以了解到 Rust 函数的基本形式: + +```rust +fn <函数名> ( <参数> ) { <参数体> } +``` + +其中 Rust 函数名称的命名风格是小写字母以下划线分割: + +```rust +fn main() { + println!("Hello, world!"); + another_function(); +} + +fn another_function() { + println!("Hello, another!"); +} +``` + +运行结果: + +```shell +Hello, world! +Hello, another! +``` + +注意,我们在源代码中的 main 函数之后定义了 another_function。Rust 不在乎您在何处定义函数,只需在某个地方定义它们即可。 + +## 函数参数 + +Rust 中定义函数如果需要具备参数必须声明参数名称和类型: + +```rust +fn main() { + another_function(5, 6); +} + +fn another_function(x: i32, y: i32) { + println!("x 的值为 :{}", x); + println!("y 的值为 :{}", y); +} +``` + +运行结果: + +```shell +x 的值为 :5 +y 的值为 :6 +``` + +## 函数体的语句和表达式 + +Rust 函数体由一系列可以以表达式(Expression)结尾的语句(Statement)组成。到目前为止,我们仅见到了没有以表达式结尾的函数,但已经将表达式用作语句的一部分。 + +语句是执行某些操作且没有返回值的步骤。例如: + +```rust +let a = 6; +``` + +这个步骤没有返回值,所以以下语句不正确: + +```rust +let a = (let b = 2); +``` + +表达式有计算步骤且有返回值。以下是表达式(假设出现的标识符已经被定义): + +```rust +a = 7 +b + 2 +c * (a + b) +``` + +Rust 中可以在一个用`{}`包括的块里编写一个较为复杂的表达式: + +```rust +fn main() { + let x = 5; + + let y = { + let x = 3; + x + 1 + }; +} +``` + +# Rust 所有权 + +计算机程序必须在运行时管理它们所使用的内存资源。 + +大多数的编程语言都有管理内存的功能: + +C/C++ 这样的语言主要通过手动方式管理内存,开发者需要手动的申请和释放内存资源。但为了提高开发效率,只要不影响程序功能的实现,许多开发者没有及时释放内存的习惯。所以手动管理内存的方式常常造成资源浪费。 + +Java 语言编写的程序在虚拟机(JVM)中运行,JVM 具备自动回收内存资源的功能。但这种方式常常会降低运行时效率,所以 JVM 会尽可能少的回收资源,这样也会使程序占用较大的内存资源。 + +所有权对大多数开发者而言是一个新颖的概念,它是 Rust 语言为高效使用内存而设计的语法机制。所有权概念是为了让 Rust 在编译阶段更有效地分析内存资源的有用性以实现内存管理而诞生的概念。 + +## 所有权规则 + +所有权有以下三条规则: + +- Rust中的每一个值都有一个变量,称为其所有者。 +- 一次只能有一个所有者。 +- 当所有者不在程序运行范围时,该值将被删除。 + +这三条规则是所有权概念的基础。 + +接下来介绍与所有权概念有关的概念。 + +## 变量范围 + +我们用下面这段程序描述变量范围的概念: + +```rust +{ + // 在声明以前,变量 s 无效 + let s = "variable"; + // 这里是变量 s 的可用范围 +} +// 变量范围已经结束,变量 s 无效 +``` + +变量范围是变量的一个属性,其代表变量的可行域,默认从声明变量开始有效直到变量所在域结束。 + +## 内存和分配 + +如果我们定义了一个变量并给它赋予一个值,这个变量的值存在于内存中。这种情况很普遍。但如果我们需要储存的数据长度不确定(比如用户输入的一串字符串),我们就无法在定义时明确数据长度,也就无法在编译阶段令程序分配固定长度的内存空间供数据储存使用。(有人说分配尽可能大的空间可以解决问题,但这个方法很不文明)。这就需要提供一种在程序运行时程序自己申请使用内存的机制----堆。本章所讲的"内存资源"都指的是堆所占用的内存空间。 + +有分配就有释放,程序不能一直占用某个内存资源。因此决定资源是否浪费的关键因素就是资源有没有及时的释放。 + +我们把字符串样例程序用 C 语言等价编写: + +```c +{ + char *s = strdup("schar"); + free(s); // 释放 s 资源 +} +``` + +很显然,Rust 中没有调用 free 函数来释放字符串 s 的资源(我知道这样在 C 语言中是不正确的写法,因为 "schar" 不在堆中,这里假设它在)。Rust 之所以没有明确释放的步骤是因为在变量范围结束的时候, Rust 编译器自动添加了调用释放资源函数的步骤。这个机制看似很简单了:它不过是帮助程序员在适当的地方添加了一个释放资源的函数调用而已。但这种简单的机制可以有效地解决一个史上最令程序员头疼的编程问题。 + +## 变量与数据交互的方式 + +变量与数据交互方式主要有移动(Move)和克隆(Clone)两种: + +### 移动 + +多个变量可以在 Rust 中以不同的方式与相同的数据交互: + +```rust +let x = 5; +let y = x; +``` + +这个程序将值 5 绑定到变量 x,然后将 x 的值复制并赋值给变量 y。现在栈中将有两个值 5。此情况中的数据是"基本数据"类型的数据,不需要存储在堆中,仅在栈中的数据的"移动"方式是直接复制,这不会花费更长的时间或更多的存储空间。"基本数据"类型有这些: + +- 所有整数类型,例如 i32、u32、i64 等。 +- 布尔类型 bool,值为 true 或 false 。 +- 所有浮点类型,f32 和 f64。 +- 字符类型 char。 +- 仅包含以上类型数据的元组(Tuples)。 + +但如果发生交互的数据在堆中就是另外一种情况: + +```rust +let s1 = String::from("hello"); +let s2 = s1; +``` + +第一步产生一个 String 对象,值为 "hello"。其中 "hello" 可以认为是类似于长度不确定的数据,需要在堆中存储。 + +第二步的情况略有不同(这不是完全真的,仅用来对比参考): + +![img](https://www.runoob.com/wp-content/uploads/2020/04/rust-ownership1.png)