Swift6.0 - 5、基本运算符

目录

    • 1、术语
    • 2、赋值运算符(a = b)
    • 3、算术运算符(+、-、*、/)
      • 3.1、余数运算符(%)
      • 3.2、一元负号运算符(-a)
      • 3.3、一元正号运算符(+a)
    • 4、复合赋值运算符(+=)
    • 5、比较运算符(==、!=、>、<、>=、<=)
    • 6、三元条件运算符(a>b ? c : d)
    • 7、空合并运算符(a ?? b)
    • 8、区间运算符
      • 8.1、闭区间运算符(a...b)
      • 8.2、半开区间运算符(a..<b)
      • 8.3、单侧区间(names[2...])
    • 8、逻辑运算符(&&、||、!)
      • 8.1、逻辑非运算符(!)
      • 8.2、逻辑与运算符(&&)
      • 8.3、逻辑或运算符(||)
      • 8.4、组合逻辑运算符
      • 8.5、显式括号

基本运算符执行赋值、算术和比较等操作。

运算符是一种特殊的符号或短语,用于检查、更改或组合值。例如,加法运算符(+)将两个数字相加,如 let i = 1 + 2,逻辑与运算符(&&)组合两个布尔值,如 if enteredDoorCode && passedRetinaScan

Swift 支持类似 C 等你已所熟知的语言中的运算符,并改进了几个功能,以消除常见的编码错误。赋值运算符(=)不返回值,以防止它被误用时等于运算符(==)被意外使用。算术运算符(+-*/%等)检测并禁止值溢出,以避免在处理超出存储它们的类型允许值范围的较大或较小数字时出现意外结果。

Swift 还提供了 C 语言中没有的区间运算符,如 a..<ba...b,作为表达值范围的快捷方式。

本章介绍了 Swift 中的常见运算符。

1、术语

运算符可以是一元、二元或三元:

  • 一元运算符:作用于单个目标(如 -a)。一元前置运算符紧跟在其目标之前(如 !b),一元后置运算符紧跟在其目标之后(如 c!)。
  • 二元运算符:作用于两个目标(如 2 + 3),是中置的,因为它们出现在两个目标之间。
  • 三元运算符:作用于三个目标。与 C 一样,Swift 只有一个三元运算符,即三元条件运算符(a ? b : c)。

运算符影响的值称为操作数。在表达式 1 + 2 中,+ 符号是一个中置运算符,它的两个操作数是值 12

2、赋值运算符(a = b)

赋值运算符:(a = b)用 b 的值初始化或更新 a 的值:

let b = 10
var a = 5
a = b
// a 现在等于 10

如果赋值运算符的右侧是一个包含多个值的元组,可以将其元素同时分解为多个常量或变量:

let (x, y) = (1, 2) // x 等于 1, y 等于 2

与 C 和 Objective-C 中的赋值运算符不同,Swift 中的赋值运算符本身不返回值。以下语句无效:

if x = y { // 这是无效的,因为 x = y 不返回值。
}

因为 Swift 语言规定 if x = y 这种写法是无效的,这个特性可以防止不小心使用赋值运算符(=) 而非等于运算符(==)。Swift 帮助你避免代码中出现这种错误。

3、算术运算符(+、-、*、/)

Swift 为所有数值类型支持四种标准算术运算符

  • 加法(+
  • 减法(-
  • 乘法(*
  • 除法(/
1 + 2       // 等于 3
5 - 3       // 等于 2
2 * 3       // 等于 6 
10.0 / 2.5  // 等于 4.0

Swift 的算术运算符与 C 和 Objective-C 中的不同,默认情况下不允许值溢出。您可以选择使用 Swift 的溢出运算符(如 a &+ b)来启用值溢出行为。

加法运算符也支持 String 拼接:

"hello, " + "world"  // 等于 "hello, world"

3.1、余数运算符(%)

余数运算符:(a % b)计算出 ba 中能容纳多少个倍数,并返回剩余的值(称为余数)。

注意: 需要注意的是,尽管余数运算符在其他语言中也被称为模运算符, 但在 Swift 中对负数的处理与模运算符有所不同。

让我们来看看余数运算符是如何工作的。 要计算 9 % 4,首先要确定 9 中可以包含多少个 4

我们可以在 9 中容纳两个 4,剩余的是 1(用橙色表示)。

在 Swift 中,这可以写作:

9 % 4    // 等于 1

为了确定 a % b 的答案,% 运算符计算以下等式并返回 余数 作为输出:

a = (b x 某个乘数) + 余数

其中 某个乘数ba 中能容纳的最大倍数。

94 代入此等式,得:

9 = (4 x 2) + 1

当计算 a 为负值时,采用相同的方法:

-9 % 4   // 等于 -1

-94 代入等式,得:

-9 = (4 x -2) + -1

因此余数值为 -1

对于 b 为负值的情况,其符号将被忽略。这意味着 a % ba % -b 总是给出相同的答案。

3.2、一元负号运算符(-a)

数值的正负号可以使用前缀 - 切换,称为一元负号运算符

let three = 3
let minusThree = -three       // minusThree 等于 -3
let plusThree = -minusThree   // plusThree 等于 3,或 "负负三"

一元负号运算符(-)直接加在它所作用的值前面,中间没有任何空格。

3.3、一元正号运算符(+a)

一元正号运算符(+)只是返回它所作用的值,不做任何改变:

let minusSix = -6
let alsoMinusSix = +minusSix  // alsoMinusSix 等于 -6

虽然一元加运算符实际上什么也没做,但是当你使用一元减运算符表示负数时,你可以使用它来使你的代码对正数也保持对称性。

4、复合赋值运算符(+=)

与 C 语言一样,Swift 提供了复合赋值运算符,它将赋值(=)与另一个操作结合起来。 一个例子是加法赋值运算符(+=):

var a = 1
a += 2
// a 现在等于 3

表达式 a += 2a = a + 2 的简写。 实际上,加法和赋值被合并成一个同时执行这两个任务的运算符。

注意: 复合赋值运算符不会返回值。 例如,你不能写 let b = a += 2

5、比较运算符(==、!=、>、<、>=、<=)

Swift 支持以下比较运算符:

  • 等于(a == b
  • 不等于(a != b
  • 大于(a > b
  • 小于(a < b
  • 大于等于(a >= b
  • 小于等于(a <= b

注意: Swift 还提供了两个标识运算符===!==), 你可以用它们来测试两个对象引用是否指向同一个对象实例。

每个比较运算符都返回一个 Bool 值来指示语句是否为真:

1 == 1   // true 因为 1 等于 1
2 != 1   // true 因为 2 不等于 1
2 > 1    // true 因为 2 大于 1 
1 < 2    // true 因为 1 小于 2
1 >= 1   // true 因为 1 大于等于 1
2 <= 1   // false 因为 2 不小于等于 1

比较运算符通常用于条件语句中,例如 if 语句:

let name = "world"
if name == "world" {print("hello, world") 
} else {print("I'm sorry \(name), but I don't recognize you")
} // 打印 "hello, world", 因为 name 确实等于 "world"。

如果两个元组具有相同的类型和相同数量的值,则可以比较它们。 元组是从左到右逐个值进行比较的,直到比较发现两个不相等的值为止。 这两个值将进行比较,并且该比较的结果决定了整个元组比较的结果。 如果所有元素都相等,那么这两个元组本身就相等。 例如:

(1, "zebra") < (2, "apple")   // 为 true,因为 1 小于 2; "zebra" 和 "apple" 未比较
(3, "apple") < (3, "bird")    // 为 true,因为 3 等于 3,而 "apple" 小于 "bird"
(4, "dog") == (4, "dog")      // 为 true,因为 4 等于 4,而 "dog" 等于 "dog"

在上面的示例中,您可以看到第一行的从左到右比较行为。 因为 1 小于 2,所以 (1, "zebra") 被认为小于 (2, "apple"),而不管元组中的任何其他值如何。 即使 "zebra" 不小于 "apple",也无关紧要,因为比较已经由元组的第一个元素决定了。 但是,当元组的第一个元素相同时,它们的第二个元素_会_进行比较 —— 这就是第二行和第三行发生的情况。

只有当给定的运算符可以应用于各自元组中的每个值时,元组才能与该运算符进行比较。例如,如下面的代码所示,您可以比较两个类型为 (String, Int) 的元组,因为 StringInt 值都可以使用 < 运算符进行比较。相反,类型为 (String, Bool) 的两个元组不能使用 < 运算符进行比较,因为 < 运算符不能应用于 Bool 值。

("blue", -1) < ("purple", 1)        // 可以,计算结果为 true
("blue", false) < ("purple", true)  // 错误,因为 < 不能比较布尔值

注意: Swift 标准库包含用于具有少于七个元素的元组的比较运算符。 要比较具有七个或更多元素的元组, 您必须自己实现比较运算符。

6、三元条件运算符(a>b ? c : d)

三元条件运算符是一种特殊的运算符,用于根据给定条件选择两个值中的一个。它由三个部分组成,语法格式为问题 ? 答案1 : 答案2。它根据问题的真假值来选择计算哪个表达式,并返回该表达式的值。如果问题为真,它会计算答案1并返回其值;否则,它会计算答案2并返回其值。

三元条件运算符是以下代码的简写形式:

if question {answer1
} else {answer2
}

下面是一个例子,用于计算表格行的高度。如果该行有标题,则行高应比内容高度高 50 点;如果该行没有标题,则行高应比内容高度高 20 点:

let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 等于 90

上面的例子是下面代码的简写形式:

let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {rowHeight = contentHeight + 50
} else {rowHeight = contentHeight + 20
}
// rowHeight 等于 90

第一个例子使用三元条件运算符意味着rowHeight可以在一行代码中设置为正确的值,这比第二个例子中使用的代码更加简洁。

三元条件运算符提供了一种有效的简写方式来决定考虑两个表达式中的哪一个。不过,要谨慎使用三元条件运算符。如果过度使用,代码的可读性会下降。避免将多个三元条件运算符实例组合成一个复合语句。

7、空合并运算符(a ?? b)

空合并运算符(a ?? b)如果可选项a包含一个值,则会解包该值,否则会返回默认值b(如果anil)。表达式a始终是一个可选类型。表达式b必须与存储在a中的类型相匹配。

空合并运算符是以下代码的简写形式:

a != nil ? a! : b

上面的代码使用三元条件运算符和强制解包(a!)来访问 a 中包装的值(当 a 不是 nil 时),否则返回 b。空合并运算符提供了一种更优雅的方式,以简洁和可读的形式封装这种条件检查和解包。

注意: 如果 a 的值是非 nil 的,则不会计算 b 的值。这被称为短路求值

下面的示例使用空合并运算符在默认颜色名称和可选用户定义的颜色名称之间进行选择:

let defaultColorName = "red"
var userDefinedColorName: String?   // 默认为 nilvar colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 为空,所以 colorNameToUse 为默认值 "red"

变量 userDefinedColorName 被定义为一个可选的 String 类型,默认值为 nil。由于 userDefinedColorName 是一个可选类型,你可以使用空合并运算符来考虑它的值。在上面的例子中,该运算符被用于确定一个名为 colorNameToUseString 变量的初始值。因为 userDefinedColorNamenil,所以表达式 userDefinedColorName ?? defaultColorName 返回 defaultColorName 的值,即 "red"

如果你给 userDefinedColorName 赋予一个非 nil 的值,并再次执行 nil 合并运算符检查,那么 userDefinedColorName 包裹的值将被使用,而不是默认值:

userDefinedColorName = "green" 
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 不是 nil,所以 colorNameToUse 被设置为 "green"

8、区间运算符

Swift 包含几个区间运算符,这些是表达一个值范围的快捷方式。

8.1、闭区间运算符(a…b)

闭区间运算符(a...b)定义了一个从 ab 的范围,包括 ab 的值。a 的值不能大于 b

闭区间运算符在需要使用所有值的情况下很有用,例如在 for-in 循环中:

for index in 1...5 {print("\(index) 乘以 5 等于 \(index * 5)") 
}
// 1 乘以 5 等于 5
// 2 乘以 5 等于 10
// 3 乘以 5 等于 15 
// 4 乘以 5 等于 20
// 5 乘以 5 等于 25

8.2、半开区间运算符(a…<b)

半开区间运算符(a..<b)定义了一个从 ab 但不包括 b 的范围。它被称为_半开_是因为它包含第一个值但不包含最后一个值。与闭区间运算符一样,a 的值不能大于 b。如果 a 等于 b,那么结果范围将是空的。

半开区间对于处理从基数 0 开始的列表(如数组)时特别有用,因为它可以计数到列表长度(但不包括列表长度):

let names = ["Anna", "Alex", "Brian", "Jack"] 
let count = names.count
for i in 0..<count {print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian 
// 第 4 个人叫 Jack

注意数组包含四个元素,但 0..<count 只计数到 3(数组中最后一个元素的索引),因为它是一个半开区间。

8.3、单侧区间(names[2…])

闭区间运算符有一种替代形式,用于一直延伸到尽可能远的区间 —— 例如,一个包含从索引 2 到数组末尾所有元素的区间。 在这些情况下,你可以省略区间运算符的一侧值。 这种区间被称为单侧区间,因为运算符只有一侧有值。 例如:

for name in names[2...] { print(name) }
// Brian
// Jackfor name in names[...2] { print(name) }
// Anna
// Alex
// Brian

半开区间运算符也有一种只写最后一个值的单侧形式。 就像在两侧都包含值时一样,最后一个值不包含在区间内。 例如:

for name in names[..<2] { print(name) }
// Anna
// Alex

单侧区间不仅可以用于下标,还可以用于其他上下文。 对于省略了第一个值的单侧区间,你不能遍历它,因为不清楚他从哪里开始迭代。 你可以遍历省略了最后一个值的单侧区间;但是,由于该区间无限延伸,请确保为循环添加一个显式的结束条件。 你还可以检查单侧区间是否包含特定值,如下面的代码所示。

let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true

8、逻辑运算符(&&、||、!)

逻辑运算符:修改或组合布尔逻辑值 truefalse。 Swift 支持 C 语言中的三个标准逻辑运算符:

  • 逻辑非(!a
  • 逻辑与(a && b
  • 逻辑或(a || b

8.1、逻辑非运算符(!)

逻辑非运算符(!a)反转布尔值,使 true 变为 falsefalse 变为 true

逻辑非运算符是一个前置运算符,紧跟在它所操作的值之前,中间没有空格。 它可以读作"非 a",如下例所示:

让我们来看一个简单的例子:

let allowedEntry = false
if !allowedEntry {print("ACCESS DENIED")
} // 打印 "ACCESS DENIED"

短语 if !allowedEntry 可以理解为 “如果不允许进入”。只有当 “不允许进入” 为真时,才会执行后续的那一行;也就是说,如果 allowedEntryfalse

正如这个例子所示,谨慎选择布尔常量和变量名可以帮助保持代码的可读性和简洁性,同时避免双重否定或令人困惑的逻辑语句。

8.2、逻辑与运算符(&&)

逻辑与运算符a && b) 创建逻辑表达式,其中两个值都必须为 true,整个表达式才为 true。如果任一值为 false,整个表达式也将为 false。事实上,如果_第一个_值为 false,第二个值甚至不会被评估,因为它无论如何都不可能使整个表达式等于 true。这被称为_短路求值_。

下面的例子考虑了两个 Bool 值,只有在两个值都为 true 时才允许访问:

let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "ACCESS DENIED"

8.3、逻辑或运算符(||)

逻辑或运算符a || b) 是由两个相邻的管道字符组成的中置运算符。你可以使用它来创建逻辑表达式,在这种表达式中,只要_其中一个_值为 true,整个表达式就为 true

与上面的逻辑与运算符一样,逻辑或运算符也使用短路求值来考虑它的表达式。如果逻辑或表达式的左侧为 true,右侧就不会被评估,因为它无法改变整个表达式的结果。

在下面的例子中,第一个 Bool 值(hasDoorKey) 为 false,但第二个值(knowsOverridePassword) 为 true。由于有一个值为 true,整个表达式也将评估为 true,因此允许访问:

let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"

8.4、组合逻辑运算符

你可以组合多个逻辑运算符来创建更长的复合表达式:

if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"

这个例子使用多个 &&|| 运算符来创建一个更长的复合表达式。然而,&&|| 运算符仍然只作用于两个值,所以这实际上是三个较小的表达式链接在一起。这个例子可以理解为:

如果我们输入了正确的门禁代码并通过了视网膜扫描,或者我们有一把有效的门钥匙,或者我们知道紧急情况下的覆盖密码,那么就允许访问。

根据 enteredDoorCodepassedRetinaScanhasDoorKey 的值,前两个子表达式为 false。然而,由于知道紧急覆盖密码,整个复合表达式仍然评估为 true

注意: Swift 逻辑运算符 &&|| 遵循从左到右的结合顺序,这意味着带有多个逻辑运算符的复合表达式会首先评估最左边的子表达式。

8.5、显式括号

有时即使不严格需要,也有必要使用括号来提高复杂表达式的可读性,让表达式的意图更加清晰。 在上面的门禁示例中,为复合表达式的第一部分添加括号是有用的,可以明确表达其意图:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"

括号明确表示前两个条件被视为整体逻辑中的一种可能状态。 虽然复合表达式的输出没有改变,但整体意图对读者来说更加清晰明了。 可读性永远比简洁性更重要,因此在有助于阐明意图的地方使用括号是很有必要的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89234.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89234.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DataWhale AI夏令营 Task2.2笔记

本次代码改进主要集中在聚类算法和主题词提取方法的优化上&#xff0c;主要包含三个关键修改&#xff1a;首先&#xff0c;将聚类算法从KMeans替换为DBSCAN。这是因为原KMeans方法需要预先指定聚类数量&#xff0c;而实际评论数据中的主题分布难以预测。DBSCAN算法能够自动确定…

自启动策略调研

广播拦截策略1.流程图广播发送├─ 特权进程&#xff08;Root/Shell&#xff09; → 放行├─ 系统进程&#xff08;UID≤1000&#xff09; → 自动启动校验 → 非法广播&#xff1f; → 拦截│ ├─ 黑名单匹配 → 拦截│ └─ 用户/白名单校验 → 受限用户&#xff1f; →…

MFC/C++语言怎么比较CString类型最后一个字符

文章目录&#x1f527; 1. 直接下标访问&#xff08;高效首选&#xff09;&#x1f50d; 2. ReverseFind 反向定位&#xff08;语义明确&#xff09;✂️ 3. Right 提取子串&#xff08;需临时对象&#xff09;⚙️ 4. 封装工具函数&#xff08;推荐健壮性场景&#xff09;⚠️…

【Cortex-M】异常中断时的程序运行指针SP获取,及SCB寄存器错误类型获取

【Cortex-M】异常中断时的程序运行指针SP获取&#xff0c;及SCB寄存器错误类型获取 更新以gitee为准&#xff1a; gitee 文章目录异常中断异常的程序运行指针SP获取SCB寄存器错误类型获取硬件错误异常 Hard fault status register (SCB->HFSR)存储器管理错误异常 SCB->C…

项目流程管理系统使用建议:推荐13款

本文分享了13款主流的项目流程管理系统&#xff0c;包括&#xff1a;1.PingCode&#xff1b;2.Worktile&#xff1b;3.泛微 E-Office&#xff1b;4.Microsoft Project&#xff1b;5.简道云&#xff1b;6.Zoho Projects&#xff1b;7.Tita 项目管理&#xff1b;8.Oracle Primave…

neovim的文件结构

在 Linux 系统中&#xff0c;Neovim 的配置文件主要存放在以下目录结构中&#xff1a; &#x1f4c1; 核心配置目录路径内容描述~/.config/nvim/主配置目录 (Neovim 的标准配置位置)~/.local/share/nvim/Neovim 运行时数据&#xff08;插件、会话等&#xff09; &#x1f5c2;️…

【网易云-header】

网易云静态页面&#xff08;1&#xff09;效果htmlcss效果 html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">&…

Android开发知识点总结合集

初级安卓开发需要掌握的知识点主要包括安卓四大组件、Context、Intent、Handler、Fragment、HandlerThread、AsyncTask、IntentService、Binder、AIDL、SharedPreferences、Activity、Window、DecorView以及ViewRoot层级关系、触摸事件分发机制、View绘制流程、自定义View。 1…

如何通过域名白名单​OVP防盗链加密视频?

文章目录前言一、什么是域名白名单​OVP防盗链二、域名白名单​OVP防盗链的实现原理三、如何实现域名白名单​OVP防盗链加密视频总结前言 用户原创视频资源面临被非法盗链、恶意嵌入的严峻挑战&#xff0c;盗用行为不仅侵蚀创作者收益&#xff0c;更扰乱平台生态秩序。域名白名…

密码学系列文(2)--流密码

一、流密码的基本概念RC4&#xff08;Rivest Cipher 4&#xff09;是由密码学家 Ron Rivest&#xff08;RSA 算法发明者之一&#xff09;于 1987 年设计的对称流加密算法。它以简单、高效著称&#xff0c;曾广泛应用于网络安全协议&#xff08;如 SSL/TLS、WEP/WPA&#xff09;…

Drools‌业务引擎

drools引擎使用 官网介绍 一、底层原理 ReteOO 网络 • 本质是一张“有向无环图”&#xff0c;节点类型&#xff1a; – Root / ObjectTypeNode&#xff1a;按 Java 类型分发事实 – AlphaNode&#xff1a;单对象约束&#xff08;age > 18&#xff09; – BetaNode&#xf…

linux的磁盘满了清理办法

今天测试系统的某个磁盘满了&#xff0c;需要看一下&#xff0c;可以看到的是&#xff0c;已经被占用百分之百了&#xff0c;某些服务运行不了了&#xff0c;需要清一下&#xff0c;这个我熟看哪个目录占用空间大cd / du -sh * ##找到占用最大&#xff0c;比如cd /home cd /hom…

阿里开源项目 XRender:全面解析与核心工具分类介绍

阿里开源项目 XRender&#xff1a;全面解析与核心工具分类介绍 在开源技术飞速发展的浪潮中&#xff0c;阿里巴巴推出的 XRender 作为专注于表单与数据可视化的开源框架&#xff0c;凭借独特的设计理念和强大功能&#xff0c;已在开发者群体中崭露头角。XRender 以 “协议驱动…

网络安全初级--搭建

一、Docker搭建apt-get install docker.io docker-compose 下载docker 配置docker代理 a.创建对应的以及对应的文件mkdir /etc/systemd/system/docker.service.dvim /etc/systemd/system/docker.service.d/http-proxy.confb.写入以下内容[Service]Environment"HTTP_PROXYh…

文心一言4.5深度评测:国产大模型的崛起之路

在⼤语⾔模型竞争⽇益激烈的今天&#xff0c;百度推出的文⼼⼀⾔4.5凭借其在中文处理上的独特优势&#xff0c;正在成为越来越 多开发者的选择。经过为期⼀周的深度测试和数据分析&#xff0c;我将从技术参数、性能表现、成本效益等多个维度&#xff0c; 为⼤家呈现这款国产⼤模…

科技的成就(六十九)

631、摄影术的先驱 1801年&#xff0c;德国物理学家约翰威廉里特&#xff08;Johann Wilhelm Ritter&#xff09;发现了紫外线。他注意到&#xff0c;太阳光谱中紫色一侧光谱之外的位置的不可见射线比紫光更快地使氯化银试剂变暗&#xff0c;他将其称为“化学射线”。后来这种射…

用Golang gRPC异步处理:释放并发性能的秘密武器

目录 章节一:为什么gRPC异步处理是并发性能的“加速器” 异步的本质:解放Goroutine的潜能 异步gRPC的适用场景 章节二:从零开始:搭建一个异步gRPC服务 准备工作:定义Protobuf 实现同步gRPC服务 迈向异步:初步改造 章节三:用Worker Pool模式榨干并发性能 Worker …

MCP终极篇!MCP Web Chat项目实战分享

目录 前言 MCP Web Chat 功能概要说明 MCP Web Chat代码调用结构说明 api动态生成MCP Server 方法一&#xff08;之前的方法&#xff09; 方法二&#xff08;现在的方法&#xff09; 做个比较 相关代码 相关问题解决说明 稳定性 由此引申而来的异步任务问题 MCP周…

破解VMware迁移难题

理解VMware迁移的常见挑战 VMware迁移过程中可能遇到的难题包括兼容性问题、性能瓶颈、数据完整性风险以及网络配置复杂性。识别这些问题是制定有效迁移策略的基础。 评估当前环境与目标环境 详细分析源VMware环境的配置、虚拟机数量、存储类型和网络拓扑。对比目标环境的硬件和…

15-STM32F103RCT6的FLASH写入

STM32F103RCT6的FLASH写入 1.//*******************************固件升级地址信息******************************// #define STM32_FLASH_BASE 0x08000000 //固件起始地址 #define FLASH_APP_ADDR 0x08005000 //APP开始地址 #define FLASH_PARA_ADDR 0x0803C000 //固件关…