当前位置: 首页 > news >正文

【2025 Rust学习 --- 11 实用工具特型01】

清理特型Drop

当一个值的拥有者消失时,Rust 会丢弃(drop)该值。丢弃一个值就必须释放 该值拥有的任何其他值、堆存储和系统资源。

丢弃可能发生在多种情况下:

  • 当变量超出作用域时;
  • 在表达式语句的末尾;
  • 当截断一个向量时,会从其末尾移除元素
struct Appellation {name: String,nicknames: Vec<String>
}

每当 Appellation 被丢弃时,Rust 都会自动清理所有这些内容,无须你进行任何进一步的编码。也可以通过实现 std::ops::Drop 特型来自定义 Rust 该如何丢弃此类型的值:

trait Drop {fn drop(&mut self);
}

Drop 的实现类似于 C++ 中的析构函数或其他语言中的终结器。

当一个值被丢弃时,如果它实现了 std::ops::Drop,那么 Rust 就会调用它的 drop 方 法,然后像往常一样继续丢弃它的字段或元素拥有的任何值。这种对 drop 的隐式调用是调用该方法的唯一途径。如果你试图显式调用该方法,那么 Rust 会将 其标记为错误

Rust 在丢弃某个值的字段或元素之前会先对值本身调用 Drop::drop,该方法收到的值仍然是已完全初始化的。因此,在 Appellation 类型的 Drop 实现 中可以随意使用其字段:

impl Drop for Appellation {fn drop(&mut self) {print!("Dropping {}", self.name);if !self.nicknames.is_empty() {print!(" (AKA {})", self.nicknames.join(", "));}println!(""); }
}
{let mut a = Appellation {name: "Zeus".to_string(),nicknames: vec!["cloud collector".to_string(),"king of the gods".to_string()]};println!("before assignment");a = Appellation { name: "Hera".to_string(), nicknames: vec![] };println!("at end of block");
}

将第二个 Appellation 赋值给 a 时,就会丢弃第一个 Appellation,而当我们离开 a 的作用域时,就会丢弃第二个 Appellation。

String 在内部使用 Vec 来保存它 的文本,因此 String 不需要自己实现 Drop,它会让 Vec 负责释放这些字符。

一个值可能会从一个地 方移动到另一个地方,但 Rust 只会丢弃它一次。

如果一个类型实现了 Drop,就不能再实现 Copy 特型了。如果类型是 Copy 类 型,就表示简单的逐字节复制足以生成该值的独立副本。

限界特型Sized

固定大小类型是指其每个值在内存中都有相同大小的类型。
Sized 是 Rust 中的一个特殊 trait,它表示一个类型在编译时具有已知的大小。这个 trait 由编译器自动实现,并且对于所有具有固定大小的类型都是默认实现的。理解 Sized 特性非常重要,因为它影响了如何使用泛型、trait 对象和其他高级特性。

Sized 的作用

  • 确保类型有已知大小当一个类型实现了 Sized trait,意味着它的大小可以在编译时确定。这对于许多操作来说是必要的,比如将值放在栈上或作为函数参数传递。

  • 默认约束:在 Rust 中,泛型参数默认要求实现 Sized trait。这意味着如果你定义了一个泛型函数或结构体,默认情况下它只能接受那些在编译时大小已知的类型。

?SizedSized 的区别

有时你可能希望放宽对类型的大小限制,允许它们可以是动态大小(DST, Dynamically Sized Type)。为此,Rust 提供了 ?Sized 语法,这表明类型不一定需要实现 Sized。例如:

fn print_type_size<T: ?Sized>(t: &T) {println!("Type T might not be sized");
}

在这个例子中,T 可以是任何类型,包括那些没有固定大小的类型,如切片 [T] 或者特质对象 dyn Trait

动态大小类型 (DST)

Rust 支持几种动态大小类型,这些类型的大小只有在运行时才能确定。常见的 DST 包括:

  • 切片 [T]
  • 特质对象 dyn Trait
  • 裸指针到 DST,如 *const [T]*mut dyn Trait

由于这些类型的大小无法在编译时确定,因此它们不能直接存储在栈上或作为普通变量使用。相反,它们通常通过指针(如 &[T]Box<dyn Trait>)来间接引用。

使用场景

  • 泛型编程:当你编写泛型代码时,默认情况下你的泛型参数是 Sized 的。如果你想让泛型参数接受动态大小类型,你需要显式地指定 ?Sized

  • 特质对象当你创建特质对象(如 Box<dyn Trait>&dyn Trait)时,特质本身并不实现 Sized,因为特质对象的实际大小是在运行时决定的。

  • 结构体和枚举如果结构体或枚举包含字段或变体,这些字段或变体必须是 Sized,除非你使用了特殊的语法(如裸指针)来处理动态大小类型。

示例代码

下面是一个简单的例子,展示了 Sized?Sized 的使用:

// 这个函数只接受具有已知大小的类型
fn only_sized<T: Sized>(t: T) {// 函数体...
}// 这个函数可以接受任何类型,包括动态大小类型
fn also_unsized<T: ?Sized>(t: &T) {// 函数体...
}struct Wrapper<T: ?Sized> {value: Box<T>,
}fn main() {only_sized(42); // OK, i32 实现了 Sized// only_sized([1, 2, 3]); // 错误,数组的大小未知also_unsized(&42); // OK, &i32 实现了 ?Sizedalso_unsized(&[1, 2, 3]); // OK, &[i32] 实现了 ?Sizedlet boxed_slice = Wrapper { value: Box::new([1, 2, 3]) };
}

only_sized 函数只能接受实现了 Sized 的类型,而 also_unsized 函数则更加灵活,它可以接受任何类型的引用,包括那些动态大小的类型。此外,Wrapper 结构体能够包含动态大小类型,因为它使用了 Box<T> 来间接持有数据。

Rust 中的几乎所有类型都是固定大小的,比如每个 u64 占用 8 字节,每个 (f32, f32, f32) 元组占用 12 字节。甚至枚举也是有大小的,也就是说,无论实际存在的是哪个变体,枚举总会占据足够的空间来容纳其最大的变体。尽管 Vec 拥有一个 大小可变的堆分配缓冲区,但 Vec 值本身是指向“缓冲区、容量和长度”的指针,因此 Vec 也是一个固定大小类型。

所有固定大小类型都实现了 std::marker::Sized 特型,该特型没有方法或 关联类型。Rust 自动为所有适用的类型实现了 std::marker::Sized 特型, 你不能自己实现它。Sized 的唯一用途是作为类型变量的限界:像 T: Sized 这样的限界要求 T 必须是在编译期已知的类型。由于 Rust 语言本身会使用这种类型的特型为具有某些特征的类型打上标记,因此我们将其称为标记特型

然而,Rust 也有一些无固定大小类型,它们的值大小不尽相同。例如,字符串 切片类型 str(注意没有 &)就是无固定大小的。字符串字面量 “diminutive” 和 “big” 是对占用了 10 字节和 3 字节的 str 切片的引用。像 [T](同样没有 &)这样的数组切片类型也是无固 定大小的,即像 &[u8] 这样的共享引用可以指向任意大小的 [u8] 切片。因为 str 类型和 [T] 类型都表示不定大小的值集,所以它们是无固定大小类型。

Rust 中另一种常见的无固定大小类型是 dyn 类型,它是特型对象的引用目标,是指向实现了给定特型的某个值的指针。例如,类型 &dyn std::io::Write 和 Box 是指向实现了 Write 特型的某个值的指针。引用目标可能是文件、网络套接字,或某种实现了 Write 的自定义类型。由于实现了 Write 的类型集是开放式的,因此dyn Write作为一个类型也是无固定大小的,也就 是说它的值可以有各种大小。

Rust 不能将无固定大小的值存储在变量中或将它们作为参数传递。你只能通过 像 &str 或 Box 这样的本身是固定大小的指针来处理它们。

指向无固定大小值的指针始终是一个胖指针,宽度为两个机器字: 指向切片的指针带有切片的长度,特型对象带有指向方法实现的虚表的指针。 特型对象和指向切片的指针在结构上很像。这两种类型,胖指针都会补齐类型中缺少的信息——它携 带着长度或虚表指针。既然欠缺静态信息,那就用动态信息来弥补。 由于无固定大小类型处处受限,因此大多数泛型类型变量应当被限制为固定大小 的 Sized 类型

事实上,鉴于这种情况的普遍性,Sized 已经成为 Rust 中的 隐式默认值:如果你写 struct S<T> { ... },那么 Rust 会将其理解为 struct S<T:Sized> { ... }。如果你不想以这种方式约束 T,就必须将 其明确地排除,写成 struct S<T:?Sized> { ... }?Sized 语法专用 于这种情况,意思是“不要求固定大小的”。如果你写 struct S <T: ?Sized>{ b: Box },那么 Rust 将允许写成 S<str> 和 S<dyn Write>,这样这 两个 Box 就变成了胖指针,而不像 S<i32> 和 S<String> 的 Box 那样只是普通指针。

尽管存在一些限制,但无固定大小类型能让 Rust 的类型系统工作得更顺畅。偶尔会遇到类型变量上的 ?Sized 限界,这几乎总是表明 “给定的类型只能通过指针访问”,并能让其关联的代码与切片对象和特型对象以及普通值一起使用。当类型变量具有?Sized限界时,它的大小不确定,既可能是固定大小,也可能不是。

【柔性数组】除了切片对象和特型对象,还有另一种无固定大小类型。结构体类型的最后一个字段(而且只能是最后一个)可以是无固定大小的,并且这样的结构体本身也是 无固定大小的。例如,Rc 引用计数指针的内部实现是指向私有类型 RcBox 的指针,后者把引用计数和 T 保存在一起。下面是 RcBox 的简化定义:

struct RcBox<T: ?Sized> {ref_count: usize, value: T,
}

Rc <T>是引用计数指针,其中的 value 字段是 Rc <T>对其进行引用计数的 T 类型。Rc<T> 会解引用成指向 value 字段的指针。ref_count 字段会保存其 引用计数。 真正的 RcBox 只是标准库的一个实现细节,无法在外部使用。但假设我们正在使用前面这种定义,那么就可以将此 RcBox 与固定大小类型一起使用,比如 RcBox <String>的结果是一个固定大小的结构体类型。

或者也可以将它与无固 定大小类型一起使用,比如 RcBox<dyn Display> 就成了无固定大小的结构体类型。 不能直接构建 RcBox<dyn Display> 值,而应该先创建一个普通的固定大小 的 RcBox,并让其 value 类型实现 Display,比如 RcBox<String>。然后 Rust 就会允许你将引用 &RcBox <String>转换为胖引用 &RcBox<dyn Display>

let boxed_lunch: RcBox<String> = RcBox {ref_count: 1,value: "lunch".to_string()
};
use std::fmt::Display;
let boxed_displayable: &RcBox<dyn Display> = &boxed_lunch;

将值传给函数时会发生隐式转换,可以将 &RcBox 传给需 要 &RcBox 的函数:

fn display(boxed: &RcBox<dyn Display>) {println!("For your enjoyment: {}", &boxed.value);
}
display(&boxed_lunch);

深拷贝特型Clone

std::clone::Clone 特型适用于可复制自身的类型。

trait Clone: Sized {fn clone(&self) -> Self;fn clone_from(&mut self, source: &Self) {  // Self类型标记*self = source.clone()}
}

clone 方法应该为 self 构造一个独立的副本并返回它。由于此方法的返回类型是 Self,并且函数本来也不可能返回无固定大小的值,因此 Clone 特型也是扩展自 Sized 特型的,进而导致其实现代码中的 Self 类型被限界成了 Sized。

克隆一个值需要为它拥有的任何值分配副本,因此 clone 无论在时间消 耗还是内存占用方面都是相当昂贵的。例如,克隆 Vec 不仅会复制 此向量,还会复制它的每个 String 元素。这就是 Rust 不会自动克隆值,而是 要求你进行显式方法调用的原因。

像 Rc 和 Arc 这样的引用计数指针类型属于例外,即克隆其中任何一个都只会增加引用计数并为你返回一个新指针。

clone_from 方法会把 self 修改成 source 的副本。clone_from 的默认定义只是克隆 source,然后将其转移给 *self。对于某些类 型,有一种更快的方法可以获得同样的效果。假设 s 和 t 都是 String。s = t.clone(); 语句必然会克隆 t,丢弃 s 的旧值,然后将克隆后的值转移给 s,这会进行一次堆分配和一次堆释放。但是如果属于原始 s 的堆缓冲区有足够的容量来保存 t 的内容,则不需要分配或释放:可以简单地将 t 的文本复制到 s 的缓冲区并调整长度。在泛型代码中,应该优先使用 clone_from,以便充分利用这种优化。

如果 Clone 实现只需要简单地对类型中的每个字段或元素进行 clone,然后从这些克隆结果中构造一个新值,并且认为 clone_from 的默认定义已经足够好了,那么 Rust 也可以帮你实现:只要在类型定义上方写 # [derive(Clone)] 就可以了。

标准库中几乎所有能合理复制的类型都实现了 Clone。不仅 bool、i32 等原始 类型实现了 Clone,String、Vec 和 HashMap 等容器类型也实现了 Clone。

而那些无法合理复制的类型(如 std::sync::Mutex)则没有实现 Clone。像 std::fs::File 这样的类型虽然可以复制,但如果操作系统无法 提供必要的资源,则复制可能会失败。这些类型也没有实现 Clone,因为 clone 必须是不会失败的。作为替代,std::fs::File 提供了一个try_clone 方法,该方法会返回一个 std::io::Result 值,用以报告失败信息。

浅拷贝特型Copy

对于大多数类型,赋值时会移动值,而不是复制它们。移动值可以更简单地跟踪它们所拥有的资源。但是也有需要复制值的场景。

如果一个类型实现了 std::marker::Copy 标记特型,那么它就是 Copy 类型,允许通过逐位复制的方式产生副本。其定义 如下所示:

trait Copy: Clone { }

Copy 是一种对语言有着特殊意义的标记特型,因此只有当类型需要一个浅层的逐字节复制时,Rust 才允许它实现 Copy拥有任何其他资源(比如堆缓冲区或操作系统句柄)的类型都无法实现 Copy

任何实现了 Drop 特型的类型都不能是 Copy 类型。Rust 认为如果一个类型需要特殊的清理代码,那么就必然需要特殊的复制代码,因此不能是 Copy 类型

可以使用 #[derive(Copy)] 让 Rust 为你派生出 Copy 实现。你会经常看到同时使用 #[derive(Copy, Clone)] 进行派生的代码。 在允许一个类型成为 Copy 类型之前务必慎重考虑。尽管这样做能让该类型更易于使用,但也对其实现施加了严格的限制。如果复制的开销很高,那么就不适合进行隐式复制

Clone和Copy区别

Copy 特性

  • 含义:当一个类型实现了 Copy 特性时,它意味着该类型的值可以被简单地通过位拷贝来复制。这意味着当你将一个值赋给另一个变量或将其作为参数传递给函数时,Rust 会自动创建该值的一个副本,而不是移动所有权。

  • 语义:对于实现了 Copy 的类型来说,复制操作是浅拷贝,并且不会影响原始数据。例如,整数、浮点数、字符以及小的固定大小的数据类型通常都是 Copy 的。

  • 性能:因为只是简单地复制内存中的位,所以 Copy 操作是非常快速和高效的。

  • 实现限制:并不是所有的类型都可以实现 Copy。特别是那些包含动态分配资源(如堆上分配的内存)或者具有非复制语义(如文件句柄或网络连接)的类型,不能实现 Copy,因为简单的位复制无法正确处理这些资源的所有权和生命周期问题。

  • 默认实现:如果一个类型只包含其他 Copy 类型,并且没有自定义析构函数(即没有实现 Drop trait),那么它可以自动派生 Copy

#[derive(Copy, Clone)]
struct Point {x: i32,y: i32,
}

Clone 特性

  • 含义Clone 特性允许你显式地调用 .clone() 方法来创建一个对象的深拷贝。这意味着对于复杂类型,Clone 可能会执行更深层次的复制逻辑,以确保新旧对象独立于彼此。

  • 语义Clone 可以用于任何需要深拷贝的场景,包括但不限于那些拥有堆分配数据的类型。开发者可以根据需要自定义 Clone 的行为,以确保正确的复制语义。

  • 性能:由于 Clone 可能涉及更深一层的数据结构复制,因此它的性能可能不如 Copy 那么高效,具体取决于实现方式。

  • 实现灵活性:几乎所有类型都可以实现 Clone,包括那些管理动态资源的类型。但是,实现者必须确保正确处理所有相关资源,避免双重释放等问题。

struct ComplexType {data: String, // String 不是 Copy 的,因为它管理了堆上的资源
}impl Clone for ComplexType {fn clone(&self) -> Self {ComplexType {data: self.data.clone(), // 手动处理深拷贝}}
}
  • Copy 提供了一种轻量级的复制机制,适用于不需要关心所有权转移的小而简单的类型;

  • Clone 则提供了一种更加通用和可控的方式来进行深拷贝,适用于各种类型,尤其是那些需要管理复杂资源的类型。

相关文章:

【2025 Rust学习 --- 11 实用工具特型01】

清理特型Drop 当一个值的拥有者消失时&#xff0c;Rust 会丢弃&#xff08;drop&#xff09;该值。丢弃一个值就必须释放 该值拥有的任何其他值、堆存储和系统资源。 丢弃可能发生在多种情况下&#xff1a; 当变量超出作用域时&#xff1b;在表达式语句的末尾&#xff1b;当…...

网络安全基础以及概念

1. 安全领域的概念 1.1 网络产品 1. EDR:终端检测与响应(Endpoint Detection and Response),终端主要包括我们的笔记本、台式机、手机、服务器等,EDR是一种运行在终端上安全软件,主要负责监控网络流量、可疑进程、注册表活动等其他安全相关的事件与活动。当发现有威胁是自…...

windows和linux的抓包方式

1.实验准备&#xff1a; 一台windows主机&#xff0c;一台linux主机 wireshark使用&#xff1a; 打开wireshark&#xff0c;这些有波动的就代表可以有流量经过该网卡&#xff0c;选择一张有流量经过的网卡 可以看到很多的流量&#xff0c;然后可以使用过滤器来过滤想要的流量…...

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…...

宝塔面板使用 GoAccess Web 日志分析教程

宝塔面板是一个简单方便的服务器运维面板,但其网站统计功能是收费的。而 GoAccess 是一个用 C 编写的免费开源 Web日志分析器,本文将介绍如何在宝塔面板中开启 GoAccess Web 日志分析功能。 内容索引 下载安装 GoAccess在宝塔面板中添加日志切割的计划任务将 Web 日志输出到…...

Windows 安装 Docker 和 Docker Compose

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …...

arcgis中用python脚本批量给多个要素类的相同字段赋值

1、python脚本 import arcpy# 设置工作空间路径 arcpy.env.workspace = r"D:\test.gdb"# 要素集名称 feature_dataset = "test"# 线要素类名称列表,初始化为空 line_feature_classes = []# 遍历要素集获取所有线要素类 for fc in arcpy.ListFeatureClass…...

目标客户营销(ABM)结合开源AI智能名片2+1链动模式S2B2C商城小程序的策略与实践

摘要&#xff1a;在数字化营销日益盛行的今天&#xff0c;目标客户营销&#xff08;Account Based Marketing, ABM&#xff09;作为一种高度定制化的营销策略&#xff0c;正逐步成为企业获取高质量客户、提升市场竞争力的重要手段。与此同时&#xff0c;开源AI智能名片21链动模…...

《异步编程之美》— 全栈修仙《Java 8 CompletableFuture 对比 ES6 Promise 以及Spring @Async》

哈喽&#xff0c;大家好&#xff01;在平常开发过程中会遇到许多意想不到的坑&#xff0c;本篇文章就记录在开发过程中遇到一些常见的问题&#xff0c;看了许多博主的异步编程&#xff0c;我只能说一言难尽。本文详细的讲解了异步编程之美&#xff0c;是不可多得的好文&#xf…...

新模型设计:Hybrid Quantum-Classical Neural Network (HQCNN) for Image Classification

新模型设计:Hybrid Quantum-Classical Neural Network (HQCNN) for Image Classification 目录 新模型设计:Hybrid Quantum-Classical Neural Network (HQCNN) for Image Classification引言1. Hybrid Quantum-Classical Neural Network 简介2. Hybrid Quantum-Classical Neu…...

iOS 中spring动画的使用

我们先来看以下两个动画的效果 上面的位移动画&#xff0c;一个是普通的动画&#xff0c;一个是spring动画&#xff0c;可以明显的看出来&#xff0c;spring动画在动画的前期更快一些&#xff0c;给人的感觉干脆&#xff0c;利落 以下是代码 - (void)normalAnimation {[UIV…...

初学stm32 --- DMA直接存储器

目录 DMA介绍 STM32F1 DMA框图 DMA处理过程 DMA通道 DMA优先级 DMA相关寄存器介绍 F1 DMA通道x配置寄存器&#xff08;DMA_CCRx&#xff09; DMA中断状态寄存器&#xff08;DMA_ISR&#xff09; DMA中断标志清除寄存器&#xff08;DMA_IFCR&#xff09; DMA通道x传输…...

校医院挂号及预约 APP 的设计与实现

标题:校医院挂号及预约 APP 的设计与实现 内容:1.摘要 随着移动互联网的发展&#xff0c;越来越多的人开始使用手机应用程序来解决生活中的各种问题。本项目旨在设计和实现一款校医院挂号及预约 APP&#xff0c;以提高校医院的服务效率和质量&#xff0c;方便师生就医。本文介…...

代理模式详解与应用

代理模式&#xff08;Proxy Pattern&#xff09;&#xff0c;也称为委托模式或 surrogate 模式&#xff0c;是一种结构型设计模式。它为其他对象提供一个代理以控制对这个对象的访问。通过引入代理对象&#xff0c;可以在不改变原始对象接口的前提下&#xff0c;添加额外的功能…...

Model-based RL自动出价算法的演进之路

▐ 导读 近年来&#xff0c;强化学习自动出价算法已成为智能投放领域的标志性技术&#xff0c;然而其所存在的在离线不一致、线上数据覆盖空间受限等关键问题尚未被完全解决。在本文中&#xff0c;我们提出一种Model-based RL&#xff08;MBRL&#xff09;自动出价算法训练新范…...

.NET AI 开发人员库 --AI Dev Gallery简单示例--问答机器人

资源及介绍接上篇 nuget引用以下组件 效果展示&#xff1a; 内存和cpu占有&#xff1a; 代码如下&#xff1a;路径换成自己的模型路径 模型请从上篇文尾下载 internal class Program{private static CancellationTokenSource? cts;private static IChatClient? model;privat…...

框架部分面试题学习

IOC容器&#xff0c;AOP IOC &#xff1a;依赖反转&#xff0c;将对象的创建&#xff0c;组装&#xff0c;管理的控制权限从应用程序反转到IOC容器中。由springboot的来实现对象的自动装配和注入。 当某个类使用了Componnet 注解后&#xff0c;标记为一个组件。那么这个类在项…...

tdengine数据库使用java连接

1 首先给你的项目添加依赖 <dependency> <groupId>com.taosdata.jdbc</groupId> <artifactId>taos-jdbcdriver</artifactId> <version>3.4.0</version> <!-- 表示依赖不会传递 --> </dependency> 注意&am…...

Java 模板变量替换——字符串替换器(思路Mybatis的GenericTokenParser)

Java 模板变量替换——字符串替换器&#xff08;思路Mybatis的GenericTokenParser&#xff09; 思路字符串替换器 思路 模板变量替换无非是寻找出字符串&#xff08;模板&#xff09;中的特殊标记&#xff0c;用对应的变量进行字符串替换。 提到变量替换&#xff0c;大家第一能…...

跨界融合:人工智能与区块链如何重新定义数据安全?

引言&#xff1a;数据安全的挑战与现状 在信息化驱动的数字化时代&#xff0c;数据已成为企业和个人最重要的资产之一。然而&#xff0c;随着网络技术的逐步优化和数据量的爆发式增长&#xff0c;数据安全问题也愈变突出。 数据安全现状&#xff1a;– 数据泄露驱动相关事件驱…...

android 自定义SwitchCompat,Radiobutton,SeekBar样式

纯代码的笔记记录。 自定义SwitchCompat按钮的样式 先自定义中间的圆球switch_thumb_bg.xml <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/android"android:shape"oval&q…...

计算机网络的定义与发展历程

计算机网络的定义 计算机网络是指通过通信设备和传输介质将分布在不同地点的计算机及其相关设备&#xff08;如打印机、服务器等&#xff09;连接起来&#xff0c;按照一定的通信协议进行数据交换与资源共享的系统。计算机网络的基本功能包括&#xff1a;信息的传输、资源共享…...

对比学习 (Contrastive Learning) 算法详解与PyTorch实现

对比学习 (Contrastive Learning) 算法详解与PyTorch实现 目录 对比学习 (Contrastive Learning) 算法详解与PyTorch实现1. 对比学习 (Contrastive Learning) 算法概述1.1 自监督学习1.2 对比学习的优势2. 对比学习的核心技术2.1 正样本对与负样本对2.2 对比损失函数2.3 数据增…...

DBeaver执行本地的sql语句文件避免直接在客户端运行卡顿

直接在客户端运行 SQL 语句和通过加载本地文件执行 SQL 语句可能会出现不同的性能表现&#xff0c;原因可能包括以下几点&#xff1a; 客户端资源使用&#xff1a; 当你在客户端界面直接输入和执行 SQL 语句时&#xff0c;客户端可能会消耗资源来维护用户界面、语法高亮、自动完…...

C++ 的 pair 和 tuple

1 std::pair 1.1 C 98 的 std::pair 1.1.1 std::pair 的构造 ​ C 的二元组 std::pair<> 在 C 98 标准中就存在了&#xff0c;其定义如下&#xff1a; template<class T1, class T2> struct pair;std::pair<> 是个类模板&#xff0c;它有两个成员&#x…...

Zookeeper 集群安装

Zookeeper 集群 主机 IP SoftWare Port OS Myidnode1 192.168.230.128 apache-zookeeper-3.7.1 2181 Centos 7 1 node2 192.168.230.129 apache-zookeeper-3.7.1...

git merge与rebase区别以及实际应用

在 Git 中&#xff0c;merge 和 rebase 是两种将分支的更改合并到一起的常用方法。虽然它们都可以实现类似的目标&#xff0c;但它们的工作方式和效果有所不同。 1. Git Merge 定义&#xff1a;git merge 是将两个分支的历史合并在一起的一种操作。当你执行 git merge 时&…...

kvm虚拟机出现应用程序无法正常启动报0xc0000142错误

场景&#xff1a;我的是window10虚拟机&#xff0c;在运行我的软件的时候&#xff0c;出现0xc0000142错误&#xff0c;原因可能是cpu型号问题&#xff0c;某些虚拟cpu可能没有特定的指令&#xff0c;只需要修改虚拟机配置文件以下参数即可...

Redis 安装与 Spring Boot 集成指南

安装 Redis 和将其与 Spring Boot 应用集成是构建高效缓存解决方案的常见步骤。以下是详细的指南&#xff0c;帮助你在本地环境中安装 Redis&#xff0c;并在 Spring Boot 项目中配置和使用它。 1. 安装 Redis Windows 环境 Redis 官方并不直接支持 Windows&#xff0c;但你…...

Flink集成TDEngine来批处理或流式读取数据进行流批一体化计算(Flink SQL)拿来即用的案例

Flink 以其流批一体化的编程模型而备受青睐。它支持高吞吐、低延迟的实时流计算,同时在批处理方面也表现出色。Flink 提供了丰富的 API,如 DataStream API 和 DataSet API,方便开发者进行数据处理操作,包括转换、聚合、连接等,使得开发者能够轻松构建复杂的数据处理逻辑。…...

南京代理注册公司机构/东莞网站seo技术

整理了一下5年前左右的一些资料 大学期间和研究生期间参加了很多数学建模比赛&#xff0c;放在网盘好久啦&#xff0c;现在把资源共享到Github上面&#xff0c;供大家参考。 github链接&#xff1a;https://github.com/XiaoGongWei/MMP MathematicalModelingPapers 数学建模…...

手机网站建设是什么/百度一下你就知道手机版官网

本文主要总结线程共享数据的相关知识&#xff0c;主要包括两方面:一是某个线程内如何共享数据&#xff0c;保证各个线程的数据不交叉&#xff1b;一是多个线程间如何共享数据&#xff0c;保证数据的一致性。线程范围内共享数据自己实现的话&#xff0c;是定义一个Map,线程为键&…...

淄博微网站/重庆seo霸屏

这是一份 JavaScript 冒泡排序的代码&#xff1a; functionbubbleSort(arr) {for (var i 0; i < arr.length - 1; i) {for (var j 0; j < arr.length - i - 1; j) {if (arr[j] > arr[j 1]) {var temp arr[j];arr[j] arr[j 1];arr[j 1] temp;}}}return arr;...

专业网站设计专家/广州网络推广公司有哪些

有其他的方法可以一起交流学习n(*≧▽≦*)n 效果图&#xff1a;css样式自己设置哟 js: let index 0; function generateDom(menusData,menusDom) {for(let menu in menusData) {let li document.createElement(li);if(typeof(menusData[menu].subMenu)"undefined"…...

在线定制logo/持续优化疫情防控举措

地址 单播地址(unicast address)最大32767(0x7FFF)&#xff0c;有Provisioner在配对的时候分配 虚拟地址(virtual address)代表一系列目标地址&#xff0c;16bit的值, 范围0x8000~0xBFFF 虚拟地址的意思&#xff1a; Label UUID是128bit的&#xff0c;一个或多个elements可以订…...

北京公司模板网站好/石家庄网络关键词排名

前面的直接插入算法&#xff0c;以抓牌为例&#xff0c;假设手气比较好&#xff0c;抓牌的顺序是从A直到K&#xff0c;那么在这整个过程中都无需进行任何的插入动作&#xff0c;只需要将每次抓到的牌放在最后即可。假设现在手上已经抓到的牌的顺序中逆序比较少&#xff0c;则抓…...