【CXX】2 CXX blobstore客户端说明
本示例演示了一个调用blobstore服务的C++客户端的Rust应用程序。事实上,我们会看到两个方向的调用:Rust到C++以及C++到Rust。对于您自己的用例,您可能只需要其中一个方向。
示例中涉及的所有代码都显示在此页面上,但它也以可运行的形式提供在demo目录中https://github.com/dtolnay/cxx.要直接尝试,请从该目录运行cargo run。
共享结构、不透明类型和函数已经在上一篇文章中叙述,不清楚的可以先去看一下。
一、创建项目
我们在命令行中创建一个空白的Cargo项目:
cargo new cxx-demo
编辑Cargo.toml文件,添加对cxx的依赖:
[dependencies]
cxx = "1.0"
二、定义语言边界
CXX依赖于对每种语言向另一种语言公开的函数签名的描述。您可以在Rust模块中使用extern块提供此描述,该模块用#[cxx::bridge]属性宏注释。
我们在项目的main.rs文件的顶部添加该内容:
#[cxx::bridge]
mod ffi {
}
该内容将是FFI边界双方需要达成一致的所有内容。
三、从Rust调用C++函数
让我们获取一个C++blobstore客户端的实例,一个在C++中定义的类blobstore client。
我们将把BlobstreClient视为CXX分类中的不透明类型,这样Rust就不需要对其实现做出任何假设,甚至不需要对它的大小或对齐方式做出任何假设。一般来说,C++类型可能有一个与Rust的move语义不兼容的move构造函数,或者可能包含Rust的借用系统无法建模的内部引用。尽管有其他选择,但在FFI边界上不关心任何此类事情的最简单方法是将其视为不透明,不需要了解类型。
不透明类型只能在间接后面操作,如引用&、Rust Box或UniquePtr(std::unique_ptr的Rust绑定)。我们将添加一个函数,通过该函数,C++可以向Rust返回std::unique_ptr。
// src/main.rs#[cxx::bridge]
mod ffi {unsafe extern "C++" {include!("cxx-demo/include/blobstore.h");type BlobstoreClient;fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;}
}fn main() {let client = ffi::new_blobstore_client();
}
即使CXX自动执行静态断言,确保签名与C++中声明的完全匹配,我们仍然需要确保键入的签名是准确的。比如new_blobstore_client函数如果会发生意外(如内存错误)必须用unsafe标记。这次是在一个安全的extern“C++”块中,因为程序员不再需要对签名进行任何安全声明。
四、添加C++代码
在CXX与Cargo的集成中,默认情况下,所有#include路径都以单元包(crate)名称开头。这就是为什么我们看到 include!(“cxx-demowj/include/blobstore.h”) ——我们将把C++头文件放在Rust单元包内的相对路径include/blostore.h处。如果根据Cargo.toml中的name字段,你的crate的名称不是cxx-demo,那么在本教程中,你需要在所有地方使用这个名称来代替cxx-demo。
// include/blobstore.h#pragma once
#include <memory>class BlobstoreClient {
public:BlobstoreClient();
};std::unique_ptr<BlobstoreClient> new_blobstore_client();// src/blobstore.cc#include "cxx-demo/include/blobstore.h"BlobstoreClient::BlobstoreClient() {}std::unique_ptr<BlobstoreClient> new_blobstore_client() {return std::unique_ptr<BlobstoreClient>(new BlobstoreClient());
}
使用std::make_unique也可以,只要你将std(“c++14”)传递给c++编译器,如稍后所述。
include/和src/中的位置并不重要;只要在整个项目中使用正确的路径,就可以将C++代码放置在单元包中的任何其他位置。
请注意,CXX不会查看这些文件中的任何一个。你可以自由地在这里放任意的C++代码, #include你自主的库等等。CXX库所做的就是针对您在头文件中提供的内容发出静态断言。
五、用Cargo编译C++代码
Cargo有一个适合编译非Rust代码的构建脚本功能。
我们需要在Cargo.toml中引入对CXX的C++代码生成器的新的构建时依赖:
# Cargo.toml[dependencies]
cxx = "1.0"[build-dependencies]
cxx-build = "1.0"
然后在Cargo.toml旁边添加一个build.rs构建脚本,以运行cxx构建代码生成器和C++编译器。相关参数是包含cxx::bridge语言边界定义的Rust源文件的路径,以及在Rust crate构建过程中要编译的任何其他C++源文件的道路。
// build.rsfn main() {cxx_build::bridge("src/main.rs").file("src/blobstore.cc").compile("cxx-demo");println!("cargo:rerun-if-changed=src/main.rs");println!("cargo:rerun-if-changed=src/blobstore.cc");println!("cargo:rerun-if-changed=include/blobstore.h");
}
他的build.rs也是您设置C++编译器标志的地方,例如,如果您想从C++14访问std::make_unique。
cxx_build::bridge("src/main.rs").file("src/blobstore.cc").std("c++14").compile("cxx-demo");
尽管还没有做任何有用的事情,该项目现在应该能够成功构建和运行。命令行输入命令如下:
<cxx-demo路径提示符> cargo runCompiling cxx-demo v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.34sRunning `target/debug/cxx-demo`<cxx-demo路径提示符>
六、从C++调用Rust函数
我们的C++blobstore支持不连续缓冲区上传的put操作。例如,我们可能正在上传一个循环缓冲区的快照,该缓冲区往往由2个部分组成,或者由于其他原因(如绳索数据结构)而分散在内存中的文件片段。
我们将通过在连续的借用块上传递迭代器来表达这一点。这与广泛使用的字节箱的Buf特性的API非常相似。在put过程中,我们将让C++回调到Rust中,以获取上传的连续块(所有块都没有在语言边界上进行复制或分配)。实际上,C++客户端可能包含一些复杂的块批处理或并行上传,所有这些都与之相关。
// src/main.rs#[cxx::bridge]
mod ffi {extern "Rust" {type MultiBuf;fn next_chunk(buf: &mut MultiBuf) -> &[u8];}unsafe extern "C++" {include!("cxx-demo/include/blobstore.h");type BlobstoreClient;fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;fn put(&self, parts: &mut MultiBuf) -> u64;}
}
任何具有self参数的签名(等同C++的this)都被认为是一个方法/非静态成员函数。如果周围的extern块中只有一个类型,则它将是该类型的方法。如果有多个类型,您可以通过在参数列表中编写self:&BlostreClient来区分方法属于哪一个。
像往常一样,现在我们需要提供extern“Rust”块声明的所有内容的Rust定义,以及extern“C++”块宣布的新签名的C++定义。
// src/main.rs// An iterator over contiguous chunks of a discontiguous file object. Toy
// implementation uses a Vec<Vec<u8>> but in reality this might be iterating
// over some more complex Rust data structure like a rope, or maybe loading
// chunks lazily from somewhere.
pub struct MultiBuf {chunks: Vec<Vec<u8>>,pos: usize,
}pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {let next = buf.chunks.get(buf.pos);buf.pos += 1;next.map_or(&[], Vec::as_slice)
}
// include/blobstore.hstruct MultiBuf;class BlobstoreClient {
public:BlobstoreClient();uint64_t put(MultiBuf &buf) const;
};
在blobstre.cc中,我们可以调用Rust next_chunk函数,该函数通过CXX代码生成器生成的头部文件main.rs.h暴露给C++。在CXX的Cargo集成中,这个生成的头文件有一个包含crate名称、crate中Rust源文件的相对路径和.rs.h扩展名的路径。
// src/blobstore.cc#include "cxx-demo/include/blobstore.h"
#include "cxx-demo/src/main.rs.h"
#include <functional>
#include <string>// Upload a new blob and return a blobid that serves as a handle to the blob.
uint64_t BlobstoreClient::put(MultiBuf &buf) const {// Traverse the caller's chunk iterator.std::string contents;while (true) {auto chunk = next_chunk(buf);if (chunk.size() == 0) {break;}contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());}// Pretend we did something useful to persist the data.auto blobid = std::hash<std::string>{}(contents);return blobid;
}
现在可以使用了
// src/main.rsfn main() {let client = ffi::new_blobstore_client();// Upload a blob.let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];let mut buf = MultiBuf { chunks, pos: 0 };let blobid = client.put(&mut buf);println!("blobid = {}", blobid);
}
运行信息如下:
cxx-demo$ cargo runCompiling cxx-demo v0.1.0Finished dev [unoptimized + debuginfo] target(s) in 0.41sRunning `target/debug/cxx-demo`blobid = 9851996977040795552
七、插曲:产生了什么?
对于好奇的人来说,很容易了解CXX为使这些函数调用工作所做的幕后工作。在CXX的正常使用过程中,您不需要这样做,但就本教程而言,这可能具有教育意义。
CXX包含两个代码生成器:一个Rust生成器(即CXX::bridge属性过程宏)和一个C++生成器。
Rust生成的代码
通过cargo-expand可以最容易地查看程序宏的输出。然后运行cargo expand ::ffi宏展开mod ffi模块。
cxx-demo$ cargo install cargo-expand
cxx-demo$ cargo expand ::ffi
您将看到一些非常令人不快的代码,涉及#[repr(C)]、#[repr©], #[link_name] 和 #[export_name].。
八、C++生成的代码
为了调试方便,cxx_build将所有生成的C++代码链接到Cargo在target/cxxbridge/下的目标目录中。
cxx-demo$ exa -T target/cxxbridge/
target/cxxbridge
├── cxx-demo
│ └── src
│ ├── main.rs.cc -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/sources/cxx-demo/src/main.rs.cc
│ └── main.rs.h -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/include/cxx-demo/src/main.rs.h
└── rust└── cxx.h -> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cxx-1.0.0/include/cxx.h
在这些文件中,您将看到语言边界中存在的任何CXX Rust类型的声明或模板(如Rust::Slicefor&[T])以及与extern函数对应的extern“C”签名。
如果CXX C++代码生成器更适合您的工作流程,它也可以作为一个独立的可执行文件提供,将生成的代码输出到stdout。
cxx-demo$ cargo install cxxbridge-cmd
cxx-demo$ cxxbridge src/main.rs
九、共享数据结构
到目前为止,上述两个方向的调用只使用了不透明类型,而不是共享结构。
共享结构是数据结构,其完整定义对两种语言都是可见的,从而可以通过值跨语言传递它们。共享结构转换为C++聚合初始化兼容结构,与Rust结构的布局完全匹配。
作为此演示的最后一步,我们将使用共享结构体BlobMetadata在Rust应用程序和C++blobstore客户端之间传递有关blob的元数据。
// src/main.rs#[cxx::bridge]
mod ffi {struct BlobMetadata {size: usize,tags: Vec<String>,}extern "Rust" {// ...}unsafe extern "C++" {// ...fn tag(&self, blobid: u64, tag: &str);fn metadata(&self, blobid: u64) -> BlobMetadata;}
}fn main() {let client = ffi::new_blobstore_client();// Upload a blob.let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];let mut buf = MultiBuf { chunks, pos: 0 };let blobid = client.put(&mut buf);println!("blobid = {}", blobid);// Add a tag.client.tag(blobid, "rust");// Read back the tags.let metadata = client.metadata(blobid);println!("tags = {:?}", metadata.tags);
}
// include/blobstore.h#pragma once
#include "rust/cxx.h"struct MultiBuf;
struct BlobMetadata;class BlobstoreClient {
public:BlobstoreClient();uint64_t put(MultiBuf &buf) const;void tag(uint64_t blobid, rust::Str tag) const;BlobMetadata metadata(uint64_t blobid) const;private:class impl;std::shared_ptr<impl> impl;
};// src/blobstore.cc#include "cxx-demo/include/blobstore.h"
#include "cxx-demo/src/main.rs.h"
#include <algorithm>
#include <functional>
#include <set>
#include <string>
#include <unordered_map>// Toy implementation of an in-memory blobstore.
//
// In reality the implementation of BlobstoreClient could be a large
// complex C++ library.
class BlobstoreClient::impl {friend BlobstoreClient;using Blob = struct {std::string data;std::set<std::string> tags;};std::unordered_map<uint64_t, Blob> blobs;
};BlobstoreClient::BlobstoreClient() : impl(new class BlobstoreClient::impl) {}// Add tag to an existing blob.
void BlobstoreClient::tag(uint64_t blobid, rust::Str tag) const {impl->blobs[blobid].tags.emplace(tag);
}// Retrieve metadata about a blob.
BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const {BlobMetadata metadata{};auto blob = impl->blobs.find(blobid);if (blob != impl->blobs.end()) {metadata.size = blob->second.data.size();std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),[&](auto &t) { metadata.tags.emplace_back(t); });}return metadata;
}
运行命令:
cxx-demo$ cargo runRunning `target/debug/cxx-demo`blobid = 9851996977040795552
tags = ["rust"]
现在您已经看到了本教程中涉及的所有代码。它可以在演示目录中以可运行的形式一起使用https://github.com/dtolnay/cxx.您可以直接运行它,而无需从该目录运行cargo run来完成上述步骤。
十、结束语
CXX的主要贡献是它为你提供了Rust与C++的互操作性,在这种互操作性中,你编写的所有Rust端代码看起来都像是在写普通的Rust,而C++端看起来也像是在编写普通的C++。
在文中,您已经看到,所涉及的代码都不像C,也不像通常危险的“FFI胶水”,容易发生泄漏或内存安全缺陷。
由不透明类型、共享类型和关键标准库类型绑定组成的表达系统使API能够在语言边界上进行设计,从而获取接口的正确所有权和借用契约。
CXX发挥了Rust类型系统和C++类型系统的优势以及程序员的直觉。一个在没有Rust背景的C++端或没有C++背景的Rust端工作的人,将能够运用他们对语言开发的所有常见直觉和最佳实践来维护正确的FFI。
相关文章:
【CXX】2 CXX blobstore客户端说明
本示例演示了一个调用blobstore服务的C客户端的Rust应用程序。事实上,我们会看到两个方向的调用:Rust到C以及C到Rust。对于您自己的用例,您可能只需要其中一个方向。 示例中涉及的所有代码都显示在此页面上,但它也以可运行的形式提…...
图数据库neo4j进阶(一):csv文件导入节点及关系
CSV 一、load csv二、neo4j-admin import<一>、导入入口<二>、文件准备<三>、命令详解 一、load csv 在neo4j Browser中使用Cypher语句LOAD CSV,对于数据量比较大的情况,建议先运行create constraint语句来生成约束 create constraint for (s:Student) req…...
3.3 学习UVM中的uvm_driver 类分为几步?
文章目录 前言1. 定义2. 核心功能3. 适用场景4. 使用方法5. 完整代码示例5.1 事务类定义5.2 Driver 类定义5.3 Sequencer 类定义5.4 测试平台 6. 代码说明7. 总结 前言 以下是关于 UVM 中 uvm_driver 的详细解释、核心功能、适用场景、使用方法以及一个完整的代码示例ÿ…...
Docker 常用命令基础详解(一)
一、Docker 初相识 在当今数字化时代,软件开发和部署的效率与灵活性成为了关键因素。Docker,作为一款开源的应用容器引擎,犹如一颗璀璨的明星,照亮了软件开发与部署的道路,为开发者们带来了前所未有的便利。它就像是一…...
机器学习之AAE(Adversarial Autoencoder,对抗自编码器)生成数据样本
对抗自编码器(Adversarial Autoencoder,AAE)是一种结合了自编码器(Autoencoder)和生成对抗网络(GAN)的方法,用于生成新数据样本。它的目标是学习到数据的潜在分布,并通过生成对抗训练来优化潜在空间,使其接近一个已知的简单分布(例如,高斯分布)。 AAE的结构和训练…...
用大模型学大模型03-数学基础 概率论 最大似然估计(MLE)最大后验估计(MAP)
https://metaso.cn/s/r4kq4Ni 什么是最大似然估计(MLE)最大后验估计(MAP)?深度学习中如何应用,举例说明。 好的,我现在需要回答关于最大似然估计(MLE)和最大后验估计&…...
名词解释:npm,cnpm,yarn,vite,vue,electron
1. npm (Node Package Manager) 读音: “N-P-M” 或者直接读作 “npm”。 npm 是 Node.js 的官方包管理器,用于安装、发布和管理 JavaScript 软件包。它允许开发者轻松地共享代码,并且可以通过命令行工具来管理依赖关系。通过 npm init 命令可以交互式…...
ESXi安装【真机和虚拟机】(超详细)
项目简介: ESXi(Elastic Sky X Integrated)是VMware公司开发的一种裸机虚拟化管理程序,允许用户在单一物理服务器上运行多个虚拟机(VM)。它直接安装在服务器硬件上,而不是操作系统之上ÿ…...
每日一题——矩阵最长递增路径
矩阵最长递增路径问题 题目描述数据范围:进阶要求:示例示例 1示例 2 题解思路算法步骤:代码实现代码解释复杂度分析总结 题目描述 给定一个 n 行 m 列的矩阵 matrix,矩阵内所有数均为非负整数。你需要在矩阵中找到一条最长路径&a…...
设置ollama接口能外部访问
为了配置Ollama以允许外网访问,你可以按照以下步骤进行操作: 确认Ollama服务已正确安装并运行: 使用以下命令检查Ollama服务的状态: bash Copy Code systemctl status ollama如果服务未运行,使用以下命令启动它&…...
TOML介绍
0 Preface/Foreword TOML,一种配置文件格式。Toms Obvious Minimal Language. 1 介绍 TOML: Toms Obvious Minimal Language,“显而易见的最小化语言 ” JSON:不支持注释 YAML:过于复杂...
macOS部署DeepSeek-r1
好奇,跟着网友们的操作试了一下 网上方案很多,主要参考的是这篇 DeepSeek 接入 PyCharm,轻松助力编程_pycharm deepseek-CSDN博客 方案是:PyCharm CodeGPT插件 DeepSeek-r1:1.5b 假设已经安装好了PyCharm PyCharm: the Pyth…...
从云原生到 AI 原生,谈谈我经历的网关发展历程和趋势
作者:谢吉宝(唐三) 编者按: 云原生 API 网关系列教程即将推出,欢迎文末查看教程内容。本文整理自阿里云智能集团资深技术专家,云原生产品线中间件负责人谢吉宝(唐三) 在云栖大会的精…...
京东 旋转验证码 分析
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向分析 使用的第三方接码平台识别…...
R18 XR L1 enhancement
这篇是R18 XR的最后一部分,主要是L1方面的增强。 这部分增强大概的背景如下。 一些 XR 应用(例如增强现实)不仅在 DL 方向需要高数据速率,在 UL 方向也需要高数据速率。如果应用需要在 UL 方向传输视频流量,则 UL 中支持的 XR 用户数量可能非常有限。因此,增加有限的时间…...
利用Java爬虫按图搜索1688商品(拍立淘):实战案例指南
在电商领域,按图搜索功能(如1688的“拍立淘”)为用户提供了更直观、便捷的购物体验。通过上传图片,用户可以快速找到与图片相似的商品。本文将详细介绍如何利用Java爬虫技术实现按图搜索1688商品,并获取其详情数据。 …...
算法-计算字符的最短距离
力扣题目:821. 字符的最短距离 - 力扣(LeetCode) 给你一个字符串 s 和一个字符 c ,且 c 是 s 中出现过的字符。 返回一个整数数组 answer ,其中 answer.length s.length 且 answer[i] 是 s 中从下标 i 到离它 最近 …...
sqlilabs--小实验
一、先盲注判断 ?id1 and sleep(2)-- 如果发现页面存在注点,使用时间盲注脚本进行注入 import requestsdef inject_database(url):name for i in range(1, 20): # 假设数据库名称长度不超过20low 48 # 0high 122 # zmiddle (low high) // 2while low &l…...
【JavaScript爬虫记录】记录一下使用JavaScript爬取m4s流视频过程(内含ffmpeg合并)
前言 前段时间发现了一个很喜欢的视频,可惜网站不让下载,简单看了一下视频是被切片成m4s格式的流文件,初步想法是将所有的流文件下载下来然后使用ffmpeg合并成一个完整的mp4,于是写了一段脚本来实现一下,电脑没有配python环境,所以使用JavaScript实现,合并功能需要安装ffmpeg,…...
腿足机器人之一- 机械与电子组件概览
腿足机器人之一机械与电子组件概览 引言机械组件骨架材料关节设计关节机械组件轴承(ings)连杆(Linkages)齿轮(Gears) 电气组件电机控制器传感器 四足机器人设计双足机器人设计波士顿Atlas机器人 引言 腿足…...
利用二分法+布尔盲注、时间盲注进行sql注入
一、布尔盲注: import requestsdef binary_search_character(url, query, index, low32, high127):while low < high:mid (low high 1) // 2payload f"1 AND ASCII(SUBSTRING(({query}),{index},1)) > {mid} -- "res {"id": payloa…...
本地部署DeepSeek Nodejs版
目录 1.下载 Ollama 2.下载DeepSeek模型 3.下载 ollama.js 1.下载 Ollama https://ollama.com/ 下载之后点击安装,等待安装成功后,打开cmd窗口,输入以下指令: ollama -v 如果显示了版本号,则代表已经下载成功了。…...
mapbox进阶,添加绘图扩展插件,绘制任意方向矩形
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…...
哈希槽算法与一致性哈希算法比较
Redis 集群模式使用的 哈希槽(Hash Slot) 算法与传统的 一致性哈希(Consistent Hashing) 算法在数据分布和节点管理上有显著的区别。以下是两者的详细比较: 1. Redis 哈希槽算法 1.1 基本原理 Redis 集群将整个数据集…...
DeepSeek+Excel 效率翻倍
2025年初,DeepSeek以惊人的效率突破技术壁垒,用极低的成本实现了与行业顶尖AI相媲美的性能,瞬间成为全球科技领域的热门话题。 那么AI工具的普及将如何改变我们的工作方式?Excel会被取代吗? 今天,珠珠带你…...
【个人开发】cuda12.6安装vllm安装实践【内含踩坑经验】
1. 背景 vLLM是一个快速且易于使用的LLM推理和服务库。企业级应用比较普遍,尝试安装相关环境,尝试使用。 2. 环境 模块版本python3.10CUDA12.6torch2.5.1xformers0.0.28.post3flash_attn2.7.4vllm0.6.4.post1 2.1 安装flash_attn 具体选择什么版本&…...
Prompt通用技巧
Prompt 的典型构成 角色:给 AI定义一个最匹配任务的角色,比如:「你是一位软件工程师」「你是一位小学老师」指示:对任务进行描述上下文: 给出与任务相关的其它背景信息(尤其在多轮交互中)。例子 : 必要时给出举例,学术中称为 one-shot learning,few-sho…...
【R语言】方差分析
一、基本术语 在R语言以及更广泛的统计学领域中,方差分析(ANOVA,即Analysis of Variance)是一种用于比较两个或更多组数据的均值是否存在显著差异的统计方法。可以使用aov()函数或其他相关函数(如anova())…...
XSS 常用标签及绕过姿势总结
XSS 常用标签及绕过姿势总结 一、xss 常见标签语句 0x01. 标签 <a href"javascript:alert(1)">test</a> <a href"x" onfocus"alert(xss);" autofocus"">xss</a> <a href"x" onclickeval(&quo…...
haproxy详解笔记
一、概述 HAProxy(High Availability Proxy)是一款开源的高性能 TCP/HTTP 负载均衡器和代理服务器,用于将大量并发连接分发到多个服务器上,从而提高系统的可用性和负载能力。它支持多种负载均衡算法,能够根据服务器的…...
「软件设计模式」工厂方法模式 vs 抽象工厂模式
前言 在软件工程领域,设计模式是解决常见问题的经典方案。本文将深入探讨两种创建型模式:工厂方法模式和抽象工厂模式,通过理论解析与实战代码示例,帮助开发者掌握这两种模式的精髓。 一、工厂方法模式(Factory Metho…...
Flutter_学习记录_数据更新的学习
Flutter 如果界面上有数据更新时,目前学习到的有3种: 第一种: 直接用 StatefulWidget组件,然后当数据更新时,调用setState的方法更新数据,页面上的数据会直接更新;第二种: 用 State…...
淘宝订单列表Fragment转场动画卡顿解决方案
如何应对产品形态与产品节奏相对确定情况下转变为『在业务需求与产品形态高度不确定性的情况下,如何实现业务交付时间与交付质量的确定性』。我们希望通过混合架构(Native 业务容器 Weex 2.0)作为未来交易终端架构的重要演进方向,…...
【状态空间方程】对于状态空间方程矩阵D≠0时的状态反馈与滑模控制
又到新的一年啦,2025新年快乐~。前几个月都没更新,主要还是因为不能把项目上的私密工作写进去,所以暂时没啥可写的。最近在山里实习,突然想起年前遗留了个问题一直没解决,没想到这两天在deepseek的加持下很快解决了&am…...
优雅的git log输出内容更加醒目
执行命令 git config --global alias.lg "log --graph --prettyformat:%C(red)%h%C(reset) - %C(yellow)%d%C(reset) %C(magenta)<%an>%C(reset) %C(cyan)(%ad)%C(reset) %C(green)%s%C(reset) (%cr) --abbrev-commit --dateformat:%Y-%m-%d %H:%M:%S"...
PySide(PyQT)使用场景(QGraphicsScene)进行动态标注的一个demo
用以标注图像的一个基本框架demo import sys from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QMainWindow, QLabel, QGraphicsPixmapItem from PySide6.QtGui import QPixmap, QPainter, QTransform from PySide6.QtCore import Qt, QPointF, S…...
LeetCode每日精进:876.链表的中间结点
题目链接:876.链表的中间结点 题目描述: 给你单链表的头结点 head ,请你找出并返回链表的中间结点。 如果有两个中间结点,则返回第二个中间结点。 示例 1: 输入:head [1,2,3,4,5] 输出:[3,4,5…...
ollama实践笔记
目录 一、linux安装文件命令: 二、启动ollama 三、linux 如何把ollama serve做为服务方式启动 四、安装deepseek-r1 五、如何在网页中使用ollama? 5.1 安装Open WebUI【不推荐】 5.2 安装ollama-webui-lite 六、Ubuntu安装docker、只需要一句话…...
联想电脑如何进入BIOS?
打开设置 下滑找到更新与安全 点击恢复和立即重新启动 选择疑难解答 选择UEFI固件设置 然后如果有重启点击重启 重启开机时一直点击FNF10进入BIOS界面...
CentOS本机配置为时间源
CentOS本机配置为时间源 安装chrony,默认已安装修改配置文件 /etc/chrony.conf客户端配置 安装chrony,默认已安装 yum -y install chrony修改配置文件 /etc/chrony.conf # cat /etc/chrony.conf | grep -Ev "^$|#" server ceph00 iburst dri…...
使用 EDOT 监测由 OpenAI 提供支持的 Python、Node.js 和 Java 应用程序
作者:来自 Elastic Adrian Cole Elastic 很自豪地在我们的 Python、Node.js 和 Java EDOT SDK 中引入了 OpenAI 支持。它们为使用 OpenAI 兼容服务的应用程序添加日志、指标和跟踪,而无需任何代码更改。 介绍 去年,我们宣布了 OpenTelemetry…...
微信小程序网络请求封装
微信小程序的网络请求为什么要封装?封装使用有什么好处? 封装的目的是为了偷懒,试想一下每次都要wx.request,巴拉巴拉传一堆参数,是不是很麻烦,有些公共的参数例如header,baseUrl是不是可以封装…...
【自学笔记】人工智能基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 人工智能重点知识点总览一、基础概念与原理1.1 人工智能定义与发展1.2 算法与数据结构1.3 数学基础 二、机器学习2.1 监督学习2.2 无监督学习2.3 强化学习 三、深度…...
Docker 常用命令基础详解(二)
四、容器操作命令 4.1 运行容器 使用docker run命令可以创建并运行一个容器,它就像是一个神奇的 “启动器”,让镜像中的应用程序在容器中运行起来。其基本语法为: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 其中,OPTIONS…...
初学java 数据库相关学习
创建数据库: 主键: unsigned primary key auto_increment 外键: foreign key(xx) references table_name(xx) 字段: 类型: int ; tinyint ;char(20);varchar(255); date; datetime; text; float(5,2); double(10,2); long; decimal(15,10) 约束:primary key; foreig…...
ARM64 Trust Firmware [一]
ARMv8 启动流程: 在《RK3568上电启动流程 [十五]》中,简单介绍了 RK3568 的上电启动过程,本篇再详细分解其启动流程。 在 ARMv8 架构中,启动流程包含多个阶段,这些阶段被称为 BL (bootloader) …...
K8S容器启动提示:0/2 nodes are available: 2 Insufficient cpu.
问题:K8S的容器启动报错0/2 nodes are available: 2 Insufficient cpu. 原因:Pod的资源请求(requests)设置不当:在Kubernetes中,调度器根据Pod的requests字段来决定哪个节点可以运行该Pod。如果一个Pod声明…...
数据结构:图论入门
图论起源于欧拉对哥尼斯堡七桥问题的解决. 他构建的图模型将陆地用点来表示, 桥梁则用线表示, 如此一来, 该问题便转化为在图中能否不重复地遍历每条边的问题. 图论的应用 地图着色 在地图着色问题中, 我们用顶点代表国家, 将相邻国家之间用边相连. 这样, 问题就转化为用最少…...
DataBase【MySQL基础夯实使用说明(下)】
MySQL数据库 🏆当领导表示关心时,您怎么回复? ⚠️不要傻傻的说应该的,这样不仅会抹杀掉你的辛苦,也让领导没办法接话! 🔔文章末尾彩蛋! 文章目录 MySQL数据库前言一、约束1.1.外键…...
Golang的多团队协作编程模式与实践经验
Golang的多团队协作编程模式与实践经验 一、多团队协作编程模式概述 在软件开发领域,多团队协作编程是一种常见的工作模式。特别是对于大型项目来说,不同团队间需要协同合作,共同完成复杂的任务。Golang作为一种高效、并发性强的编程语言&…...