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

初次体验Tauri和Sycamore (2)

原创作者:庄晓立(LIIGO)
原创时间:2025年2月8日(首次发布时间)
原创链接:https://blog.csdn.net/liigo/article/details/145520637
版权所有,转载请注明出处。
关键词:Sycamore, Tauri, Dioxus, Leptos, Rust, WebAssembly, Reactive, JSX, React, Web

tauri-splash

前言

Tauri 2.0发布于2024年10月2日,Sycamore 0.9发布于2024年11月1日。二者在近期双双发布重大版本升级,是我(LIIGO)这次想体验他们的主要动机。Tauri自2022年发布v1.0之后就早已火出天际,而Sycamore自2022发布v0.8之后沉寂了两年之久,如今各自凤凰涅槃,他们的组合体会擦出怎样的火花?

这是上一篇体验Tauri 2.0的姊妹篇。本文重点是体验Sycamore 0.9。

关于Sycamore

Sycamore, a library that makes it effortless to write performant user interfaces using the power of fine-grained reactivity. Sycamore uses open web standards such as WebAssembly to run your Rust code on the web, an environment that has been traditionally dominated by JavaScript.

Sycamore库提供细粒度响应式能力,可轻松编写高性能UI应用。Sycamore使用WEB标准技术WebAssembly等,将你的Rust代码运行在WEB中(传统上此类应用由JavaScript主导)。

Sycamore使用类似于JSX的声明式DSL语言描述UI,并提供组件、事件、路由、双向数据绑定等功能。

Sycamore和Tauri的关系

Tauri负责整个GUI应用框架,Sycamore在框架中负责前端UI渲染。Sycamore也可以脱离Tauri独立工作,用于开发基于WASM的WEB前端应用。

创建App

本节内容主要摘抄自同系列文章第一篇《初次体验Tauri和Sycamore (1)》。

Tauri使用两个命令行工具 (create-tauri-app, tauri-cli) 创建和编译打包App。首先要安装这两个CLI:

cargo install create-tauri-app --locked
cargo install tauri-cli --version "^2.0.0" --locked

create-tauri-app, tauri-cli 从Rust源码编译(cargo install)都相当耗时(均依赖数百个crates)。我还是建议自行下载编译后版本放到cargo bin目录。我给他们提了建议,今后会推荐使用 cargo binstall 下载编译好的二进制CLI,而不是使用cargo install从源码开始编译。

这两个CLI也有都对应的npm包:create-tauri-app, @tauri-apps/cli,二者都是间接调用Rust编译好的可执行文件。供TS/JS前端使用。

执行如下命令开始创建Tauri app:cargo create-tauri-app。CLI会逐步引导你输入或选择如下信息:

  • 项目名称(Project name),默认是"tauri-app"
  • Identifier 默认是"com.tauri-app.app"
  • 前端语言,可选 Rust, TS/JS, .Net
  • UI模板,视前端语言而定
    • Rust UI模板:可选 Vanilla, Yew, Leptos, Sycamore, Dioxus
    • TS/JS UI模板:可选 Vanilla, Vue, Svelte, React, Solid, Angular, Preact
    • .Net UI模板:可选 Blazor

选TS/JS的UI模板前还需要选择包管理器:pnpm, yarn, npm, deno, bun

因为这次我(Liigo)想体验Tauri+Sycamore,因而前端语言选Rust,UI模板选Sycamore。

目录结构

Tauri+Sycamore App目录结构:

├─ public/
├─ src/
│  ├─ app.rs
│  └─ main.crs
├─ src-tauri/
│  ├─ ...
│  ├─ Cargo.toml
│  └─ tauri.conf.json
├─ .gitignore
├─ .taurignore
├─ Cargo.toml
├─ index.html
├─ README.md
├─ styles.css
└─ Trunk.toml

Tauri源码目录对前端和后端代码进行了隔离。后端代码使用src-tauri/子目录;前端代码使用除此之外的其他文件和子目录。

编译打包

本节内容主要摘抄自同系列文章第一篇《初次体验Tauri和Sycamore (1)》。

开发版

cargo tauri dev

编译完成后自动启动App,弹出GUI主窗口。允许开发者在App运行过程中修改前端源代码,Tauri(或者说Trunk)会自动编译,并刷新App窗口内容,但是App并不会中途退出或重启(原理:Trunk通过WebSocket向开发版App推送重新加载UI的指令;Dioxus虽然没用Trunk但也实现了类似机制)。

它会检查Trunk是否存在,不存在的话会自动下载源码并编译。但是在Windows下编译Trunk很可能会碰到如下问题(间接依赖openssl开发者库):

  It looks like you're compiling for MSVC but we couldn't detect an OpenSSLinstallation. If there isn't one installed then you can try the rust-opensslREADME for more information about how to download precompiled binaries ofOpenSSL:https://github.com/sfackler/rust-openssl#windowsnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: failed to compile `trunk v0.21.2`, intermediate artifacts can be found at `E:\tmp\RUST_DIR\CARGO_TARGET_DIR`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

我找到的解决办法是,去github的trunk官方仓库下载编译好的trunk.exe,丢进cargo bin目录即可(或任意PATH目录均可)。

如果cargo tauri dev过程中看到如下提示时只需耐心等待:

Warn Waiting for your frontend dev server to start on http://localhost:1420/…

这是因为Trunk先启动了(WEB服务监听1420端口),等待APP主动连接。但是编译App需要时间,等它编译完并启动后才能连上。

通过App窗口右键菜单"检查"可以打开devtools。在App运行过程中,还可以在浏览器中打开 http://localhost:1420/ ,网页外观和功能跟App窗口是一样的(可视为App的另一个实例)。

发行版

cargo tauri build

编译App并打包为安装包。

如果编译过程中提示正在下载Wix但失败(Github国内连接不稳定):

Downloading https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip

你可以通过其他方法手动下载此连接,解压到如下目录:C:\Users\liigo\AppData\Local\tauri\WixTools314\(里面有一堆exe等文件)。

此方法是我(LIIGO)从 Tauri仓库源码 里扒出来的。实证管用。

同理,如果NSIS也下载不了,可以用类似的办法手动下载解压到目录C:\Users\liigo\AppData\Local\tauri\NSIS。但是我没用这个方法。因为我觉得,既然已经有Wix用来生成MSI安装包,就没必要再下载NSIS用来生成另一种安装包。我研究了一下,将配置文件tauri.conf.json里面的bundle.targets改为"msi"(原来是"all")即可禁用NSIS等。

文件大小

Tauri+Sycamore app发行版编译后是一个可独立运行的图形用户界面(GUI)exe,其内部整合了wasm/css/图片等文件,没有其他外部依赖。exe文件大小是10.3MB,对应的安装包msi文件大小是3.6MB(安装后也只有那个exe和一个用于卸载的快捷方式文件(指向系统文件msiexec.exe /x))。Sycamore生成的wasm文件大小为750KB(已包含在exe中)。App启动时有大约一两秒的窗口白屏。

作为对比,再看一下Tauri+Dioxus app的数据:exe大小10.6MB,msi大小3.9MB,wasm文件大小为1.3MB(debug版33MB或25MB),也有一两秒的启动白屏。大同小异吧。我(LIIGO)暂且认为这是Tauri App (Hello world)的平均水平。

这样的文件大小应该很香吧。最起码比Electron app香多了。

1MB的wasm文件,用在普通网站上,网络传输加载延迟是一个较大的负担,但是对Tauri app这种桌面应用而言,就是本地加载啊,性能没得说。况且Tauri还应用了"localhost free"技术,直接注入Webview,连本地WEB传输步骤也省了。

Instead of relying on localhost server that expose your frontend to all other processes we use native webview apis to inject the assets right before the webview requests hit the network stack. – FabianLars

资源占用

Tauri+Sycamore app发行版启动后,内部加载3到6个Webview2进程,连同exe合计占用内存60到90MB。

无操作时CPU占用率为0%;在app窗口上移动鼠标时,CPU占用率逐步上升到10%甚至更多。这个问题是不是需要改善呀。

20241230 LIIGO补记:在VsCode中打开Tauri+Sycamore app项目源码,VsCode大概占用2.5GB内存甚至更多。

Tauri+Dioxus app的表现与之类似。

前端代码全览

以下是Tauri CLI生成的前端核心文件src\app.rs全部代码,先整体感受一下Sycamore。

其主体代码定义了一个App组件(App函数)。App组件内部负责描述UI、管理状态、处理事件。

use serde::{Deserialize, Serialize};
use sycamore::futures::spawn_local_scoped;
use sycamore::prelude::*;
use sycamore::web::events::SubmitEvent;
use wasm_bindgen::prelude::*;#[wasm_bindgen]
extern "C" {#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}#[derive(Serialize, Deserialize)]
struct GreetArgs<'a> {name: &'a str,
}#[component]
pub fn App() -> View {let name = create_signal(String::new());let greet_msg = create_signal(String::new());let greet = move |e: SubmitEvent| {e.prevent_default();spawn_local_scoped(async move {// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/let args = serde_wasm_bindgen::to_value(&GreetArgs {name: &name.get_clone()}).unwrap();let new_msg = invoke("greet", args).await;greet_msg.set(new_msg.as_string().unwrap());})};view! {main(class="container") {h1 {"Welcome to Tauri + Sycamore"}div(class="row") {a(href="https://tauri.app", target="_blank") {img(src="public/tauri.svg", class="logo tauri", alt="Tauri logo")}a(href="https://sycamore.dev", target="_blank") {img(src="public/sycamore.svg", class="logo sycamore", alt="Sycamore logo")}}p {"Click on the Tauri and Sycamore logos to learn more."}form(class="row", on:submit=greet) {input(id="greet-input", bind:value=name, placeholder="Enter a name...")button(r#type="submit") {"Greet"}}p {(greet_msg)}}}
}

声明式UI

Sycamore使用view!()宏描述UI,大致类似于React系的JSX语言。

语法上相对比较陌生。虽然本质上还是写HTML,但并未直接采用HTML或JSX语法,也未直接采用Rust语法,它最终呈现给我们的是一种糅合了函数调用和花括号子块的形式(form(attr1, attr2) { sub-nodes })。内部支持///* */注释。

view! {h1 {"Welcome to Tauri + Sycamore"}form(class="row", on:submit=greet) {input(id="greet-input", bind:value=name, placeholder="Enter a name...")button(r#type="submit") {"Greet"}}p {(greet_msg)}
}

在前端声明式UI语法上,不同的作者有不同的喜好倾向。LIIGO本人的感受是,Leptos更像JSX,Dioxus更像Rust,Sycamore则介于二者中间。主要区别是风格口味,暂且不谈孰好孰坏吧。总之它们都可以统一归结为“类JSX”或者“神似JSX”学派。

组件

在Sycamore中创建定义组件是非常简单的。组件有几个特征:普通的函数,添加#[component]标注,返回值类型固定为View,函数体主体是view!宏调用,里面是类JSX语法。组件函数内部view!前面,可以定义状态变量,可以写Rust代码;view!内部也可以嵌入Rust表达式;参见后文状态管理一节。

#[component]
pub fn Hello() -> View {view! {div {"hello"}}
}

我照猫画虎把前面app.rs里面的一部分UI提取为一个独立组件,welcome组件:

#[component]
fn welcome() -> View {view! {h1 {"Welcome to Tauri + Sycamore"}div(class="row") {a(href="https://tauri.app", target="_blank") {img(src="public/tauri.svg", class="logo tauri", alt="Tauri logo")}a(href="https://sycamore.dev", target="_blank") {img(src="public/sycamore.svg", class="logo sycamore", alt="Sycamore logo")}}p {"Click on the Tauri and Sycamore logos to learn more."}}
}

调用端语法示例:

#[component]
pub fn App() -> View {view! {self::welcome {}}
}

welcome前面必须加上self::前缀,否则编译报错:

error[E0425]: cannot find function welcome in module sycamore::rt::tags

看样子它固定去sycamore::rt::tagsmodule里加载组件,无视welcome就在当前module里。希望后续改进。


组件当然也可以有属性(Attributes),附官方示例定义代码和调用代码。

#[component(inline_props)]
fn Button(// `html` means that we are spreading onto an HTML element.// The other possible value is `svg`.//// `button` means that we are spreading onto a `<button>` element.#[prop(attributes(html, button))]attributes: Attributes,// We can still accept children.children: Children,// We can still accept other props besides `attributes`.other_prop: i32,
) -> View {view! {// The spread (`..xyz`) syntax applies all the attributes onto the element.button(..attributes)}
}
view! {Button(// Pass as many HTML attributes/events as you want.id="my-button",class="btn btn-primary",on:click=|_| {}// You can still pass in regular props as well.other_prop=123,) {// Children still gets passed into the `children` prop."Click me"}
}

状态管理

使用create_signal等函数创建状态对象,例如:

let name = create_signal(String::new());
let greet_msg = create_signal(String::new());

显示状态对象的值(小括号括住):

view! {p {(greet_msg)}
}

文本内插值:"ok " (greet_msg) " yes"。状态值必须写在常量文本双引号外面,严格来说是伪内插值;Leptos也类似(小括号改为花括号);Dioxus支持"ok {greet_msg} yes"真内插值。

更新状态对象的值(Signal<T>::set):

greet_msg.set(new_value);

双向绑定到组件属性(属性value⇄状态name),语法:bind:属性=状态,示例:

view! {input(id="greet-input", bind:value=name)
}

事件

以下示例代码处理FORM组件的submit事件,其中事件处理函数greet是一个闭包函数(有一个event参数,类型取决于具体事件):

let greet = move |e: SubmitEvent| {// ...
};view! {form(class="row", on:submit=greet) {// ...}
}

事件处理函数通常是被写成组件函数内部的闭包函数形式,这是因为事件处理函数内往往需要访问状态对象(Signal<T>),而状态对象往往是组件函数内部的局部变量,在组件函数内部定义的闭包函数访问组件函数内的局部变量是很方便的(自动捕获闭包外部变量)。

但是这种形式把逻辑代码和UI代码放在一个组件函数里,很容易导致大函数缝合怪,一大坨事件处理代码 + 一大坨UI描述代码(view!{}),互相喧宾夺主。我感觉组件函数的主体应该是view!{}(加上少量状态对象定义代码),理想情况下应该把事件处理代码隔离出去。

事件处理代码当然也可以写成独立函数的形式(独立于组件函数),我(LIIGO)专门做了一些尝试并且也成功了(不知道能不能作为最佳实践)。首先要解决Signal对象不在当前作用域的问题,需要通过参数传递Signal,可是有了Signal参数这函数就不可能符合事件处理函数的原型(有且只有一个Event参数)。我的做法是让这个函数执行后再返回符合事件处理函数原型的闭包函数。代码如下,mygreet()为独立函数,调用mygreet()后返回事件处理函数:

#[component]
pub fn App() -> View {let name = create_signal(String::from("LIIGO"));let greet_msg = create_signal(String::new());view! {form(class="row", on:submit=mygreet(name, greet_msg)) {// ...}}
}fn mygreet(name: Signal<String>, greet_msg: Signal<String>) -> impl Fn(SubmitEvent) {move |e| {let new_msg = invoke("greet", args).await;greet_msg.set(new_msg.as_string().unwrap());}
}

整改后的app.rs

以下是我整改后的app.rs文件全部代码,主要是拆解、抽象、隔离,但保持原有功能不变。

use serde::{Deserialize, Serialize};
use sycamore::futures::spawn_local_scoped;
use sycamore::prelude::*;
use sycamore::web::events::SubmitEvent;
use wasm_bindgen::prelude::*;#[wasm_bindgen]
extern "C" {#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}#[derive(Serialize, Deserialize)]
struct GreetArgs<'a> {name: &'a str,
}#[component]
pub fn App() -> View {let name = create_signal(String::from("LIIGO"));let greet_msg = create_signal(String::new());view! {main(class="container") {self::welcome {}form(class="row", on:submit=mygreet(name, greet_msg)) {input(id="greet-input", bind:value=name, placeholder="Enter a name...")button(r#type="submit") {"Greet"}}p {(greet_msg)}}}
}fn mygreet(name: Signal<String>, greet_msg: Signal<String>) -> impl Fn(SubmitEvent) {move |e| {print!("{}", name.get_clone());e.prevent_default();spawn_local_scoped(async move {// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/let args = serde_wasm_bindgen::to_value(&GreetArgs {name: &name.get_clone()}).unwrap();let new_msg = invoke("greet", args).await;greet_msg.set(new_msg.as_string().unwrap());})}
}#[component]
fn welcome() -> View {view! {h1 {"Welcome to Tauri + Sycamore"}div(class="row") {a(href="https://tauri.app", target="_blank") {img(src="public/tauri.svg", class="logo tauri", alt="Tauri logo")}a(href="https://sycamore.dev", target="_blank") {img(src="public/sycamore.svg", class="logo sycamore", alt="Sycamore logo")}}p {"Click on the Tauri and Sycamore logos to learn more."}}
}

Sycamore / Leptos / Dioxus

这三者有诸多相似性:

  • 都具备响应式WEB功能
  • 都提供类似于JSX的前端UI描述语言
  • 都支持UI组件化
  • 都是用Rust编程语言开发的开源项目
  • 都支持编译为WebAssembly(WASM)在浏览器内运行
  • 都可以作为Rust前端被集成进Tauri 2.0 App

当然它们也都可以脱离Tauri各自独立开发WEB应用(其中Dioxus还可以开发桌面应用和移动应用)。

三者之中目前只有Dioxus支持热加载(Hot Module Reloading, HMR),修改UI代码后无需重新编译即时预览结果,开发体验更佳。

相关文章:

初次体验Tauri和Sycamore (2)

原创作者&#xff1a;庄晓立&#xff08;LIIGO&#xff09; 原创时间&#xff1a;2025年2月8日&#xff08;首次发布时间&#xff09; 原创链接&#xff1a;https://blog.csdn.net/liigo/article/details/145520637 版权所有&#xff0c;转载请注明出处。 关键词&#xff1a;Sy…...

Qt - 地图相关 —— 2、Qt调用百度在线地图功能示例全集,包含线路规划、地铁线路查询等(附源码)

效果:由于录制软件导致exe显示不正常,实际运行没有任何问题。 作者其他相关文章链接:           Qt - 地图相关 —— 1、加载百度在线地图(附源码)...

ffmpeg基本用法

一、用法 ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... 说明&#xff1a; global options&#xff1a;全局选项&#xff0c;应用于整个 FFmpeg 进程&#xff0c;它们通常不受输入或输出部分的限制。 infile options&#xff1a;输入选…...

redis底层数据结构——链表

文章目录 定义内部实现总结 定义 链表提供了高效的节点重排能力&#xff0c;以及顺序性的节点访间方式&#xff0c;并且可以通过增删节点来灵活地调整链表的长度。 作为一种常用数据结构&#xff0c;链表内置在很多高级的编程语言里面&#xff0c;因为Redis使用的C语言并没有…...

Repo命令使用

repo 命令与 git 类似&#xff0c;但它主要用于管理多个 Git 仓库的操作。以下是等效的 repo 命令&#xff1a; 1. 获取新仓库代码 克隆仓库 repo init -u <manifest_url> -b <branch_name> repo sync repo init&#xff1a;初始化 repo&#xff0c;指定远程清单…...

React 高级教程

使用 React 高级组件(HOC)实现的完整项目示例,包含权限控制、数据加载状态处理、性能优化等常见高级功能。创建一个简单的博客系统: // 项目结构: src/ |-- components/ | |-- ArticleList.jsx | |-- Article.jsx | |-- Header.jsx | |-- LoginForm.jsx | |-- U…...

Linux: ASoC 声卡硬件参数的设置过程简析

文章目录 1. 前言2. ASoC 声卡设备硬件参数2.1 将 DAI、Machine 平台的硬件参数添加到声卡2.2 打开 PCM 流时将声卡硬件参数配置到 PCM 流2.3 应用程序对 PCM 流参数进行修改调整 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&am…...

网络基础知识与配置

目录 网络基础知识 &#xff08;一&#xff09;网络的概念 &#xff08;二&#xff09;网络协议 &#xff08;三&#xff09;网络拓扑结构 &#xff08;四&#xff09;IP地址和子网掩码 显示和配置网络接口 &#xff08;一&#xff09;在Windows系统中 &#xff08;二&a…...

【STM32】ADC|多通道ADC采集

本次实现的是ADC实现数字信号与模拟信号的转化&#xff0c;数字信号时不连续的&#xff0c;模拟信号是连续的。 1.ADC转化的原理 模拟-数字转换技术使用的是逐次逼近法&#xff0c;使用二分比较的方法来确定电压值 当单片机对应的参考电压为3.3v时&#xff0c;0~ 3.3v(模拟信…...

centos 7 关于引用stdatomic.h的问题

问题&#xff1a;/tmp/tmp4usxmdso/main.c:6:23: fatal error: stdatomic.h: No such file or directory #include <stdatomic.h> 解决步骤&#xff1a; 1.这个错误是因为缺少C编译器的标准原子操作头文件 stdatomic.h。在Linux系统中&#xff0c;我们需要安装开发工具…...

用语言模型探索语音风格空间:无需情感标签的情 感TTS

用语言模型探索语音风格空间&#xff1a;无需情感标签的情感TTS 原文&#xff1a;Exploring speech style spaces with language models: Emotional TTS without emotion labels 今天我们要说的是 一种无需情感标签的情感TTS。提出了一个基于FastSpeech2的E-TTS框架&#xff0…...

将Excel中的图片保存下载并导出

目录 效果演示 注意事项 核心代码 有需要将excel中的图片解析出来保存到本地的小伙子们看过来&#xff01;&#xff01;&#xff01; 效果演示 注意事项 仅支持xlsx格式&#xff1a;此方法适用于Office 2007及以上版本的.xlsx文件&#xff0c;旧版.xls格式无法使用。 图片名…...

2.11日学习总结

题目一 &#xff1a; AC代码 #include <stdio.h> #include <stdlib.h>// 定义长整型 typedef long long ll;// 定义求最大值和最小值的宏函数 #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))// 定义数组和变量 ll…...

安川伺服控制器MP系列优势特点及行业应用

在工业自动化领域&#xff0c;运动控制器的性能直接决定了设备的精度、效率和可靠性。作为全球领先的运动控制品牌&#xff0c;安川电机伺服控制器凭借其卓越的技术优势和广泛的应用场景&#xff0c;正在为智能制造注入强劲动力&#xff01; MP3100&#xff1a;主板型运动控制…...

【腾讯地图】录入经纬度功能 - 支持地图选点

目录 效果展示代码引入地图服务地址弹框中输入框 - 支持手动输入经纬度/地图选点按钮地图选点弹框组件 当前文章 - 地图功能与 https://blog.csdn.net/m0_53562074/article/details/143677335 功能类似 效果展示 代码 引入地图服务地址 public/index.html <!-- 互联网地图…...

Mybatis快速入门与核心知识总结

Mybatis 1. 实体类&#xff08;Entity Class&#xff09;1.1 实体类的定义1.2 简化编写1.2.1 Data1.2.2 AllArgsConstructor1.2.3 NoArgsConstructor 2. 创建 Mapper 接口2.1 Param2.2 #{} 占位符2.3 SQL 预编译 3. 配置 MyBatis XML 映射文件&#xff08;可选&#xff09;3.1 …...

RK3568平台开发系列讲解(调试篇)网卡队列均衡负载

🚀返回专栏总目录 文章目录 一、RPS 的介绍1. RPS 的工作原理2. RPS 配置3. 启用和调优 RPS4. RPS 优势二、下行测试iperf测试沉淀、分享、成长,让自己和他人都能有所收获!😄 RPS(Receive Packet Steering) 是一种用于提高网络接收性能的技术,通常用于多核处理器系统中…...

Matlab机械手碰撞检测应用

本文包含三个部分&#xff1a; Matlab碰撞检测的实现URDF文件的制作机械手STL文件添加夹爪 一.Matlab碰撞检测的实现 首先上代码 %% 检测在结构环境中机器人是否与物体之间发生碰撞情况&#xff0c;如何避免&#xff1f; % https://www.mathworks.com/help/robotics/ug/che…...

【前端】几种常见的跨域解决方案代理的概念

几种常见的跨域解决方案&代理的概念 一、常见的跨域解决方案1. 服务端配置CORS&#xff08;Cross-Origin Resource Sharing&#xff09;&#xff1a;2. Nginx代理3. Vue CLI配置代理&#xff1a;4 .uni-app在manifest.json中配置代理来解决&#xff1a;5. 使用WebSocket通讯…...

服务器有多少线程?发起一个请求调用第三方服务,是新增加一个请求吗?如果服务器线程使用完了怎么办?

目录 1. 服务器有多少线程? (1)服务器类型 (2)配置参数 (3)硬件资源 2. 发起一个请求调用第三方服务,是新增加一个线程吗? (1)同步调用 (2)异步调用 (3)HTTP 客户端 3. 如果服务器线程使用完了怎么办? (1)请求被拒绝 (2)性能下降 (3)解决方案…...

【Spring AI】基于SpringAI+Vue3+ElementPlus的QA系统实现一

整理不易&#xff0c;请不要吝啬你的赞和收藏。 1. 前言 这是 SpringAI 系列的第二篇文章&#xff0c;这篇文章将介绍如何基于 RAG 技术&#xff0c;使用 SpringAI Vue3 ElementPlus 实现一个 Q&A 系统。本文使用 deepseek 的 DeepSeek-V3 作为聊天模型&#xff0c;使用…...

前端快速生成接口方法

大家好&#xff0c;我是苏麟&#xff0c;今天聊一下OpenApi。 官网 &#xff1a; umijs/openapi - npm 安装命令 npm i --save-dev umijs/openapi 在根目录&#xff08;项目目录下&#xff09;创建文件 openapi.config.js import { generateService } from umijs/openapi// 自…...

【Qt 常用控件】多元素控件(QListWidget、QTabelWidgt、QTreeWidget)

**View和**Widget的区别&#xff1f; **View的实现更底层&#xff0c;**Widget是基于**View封装实现的更易用的类型。 **View使用MVC结构 MVC是软件开发中 经典的 软件结构 组织形式&#xff0c;软件设计模式。 M&#xff08;model&#xff09;模型。管理应用程序的核心数据和…...

java 读取sq3所有表数据到objectNode

1.实现效果&#xff1a;将sq3中所有表的所有字段读到objectNode 对象中&#xff0c;兼容后期表字段增删情况&#xff0c;数据组织形式如下图所示&#xff1a; 代码截图&#xff1a; 代码如下&#xff1a; package com.xxx.check.util;import java.sql.*; import java.util.Arr…...

react redux用法学习

参考资料&#xff1a; https://www.bilibili.com/video/BV1ZB4y1Z7o8 https://cn.redux.js.org/tutorials/essentials/part-5-async-logic AI工具&#xff1a;deepseek&#xff0c;通义灵码 第一天 安装相关依赖&#xff1a; 使用redux的中间件&#xff1a; npm i react-redu…...

C++20中的std::atomic_ref

一、std::atomic_ref 我们在学习C11后的原子操作时&#xff0c;都需要提前定义好std::atomic变量&#xff0c;然后才可以在后续的应用程序中进行使用。原子操作的优势在很多场合下优势非常明显&#xff0c;所以这也使得很多开发者越来习惯使用原子变量。 但是&#xff0c;在实…...

encodeURI(),encodeURIComponent()区别

encodeURI()&#xff0c;encodeURIComponent()区别 encodeURI(): 对整个url(链接/网络链接)进行编码。 对中文&#xff0c;完全编码。 对英文不带空格则不会编码&#xff0c;带空格则会对空格编码。 解码&#xff1a;decodeURI() 例如&#xff1a; let ChineseUrl "htt…...

Selenium:网页frame与多窗口处理

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、多窗口处理 1.1、多窗口简介 点击某些链接&#xff0c;会重新打开⼀个窗⼜&#xff0c;对于这种情况&#xff0c;想在新页⾯上操作&#xff0c;就 得先切换窗…...

自动驾驶---如何打造一款属于自己的自动驾驶系统

在笔者的专栏《自动驾驶Planning决策规划》中&#xff0c;主要讲解了行车的相关知识&#xff0c;从Routing&#xff0c;到Behavior Planning&#xff0c;再到Motion Planning&#xff0c;以及最后的Control&#xff0c;笔者都做了相关介绍&#xff0c;其中主要包括算法在量产上…...

开源机器人+具身智能 解决方案+AI

开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...

【web自动化】指定chromedriver以及chrome路径

selenium自动化&#xff0c;指定chromedriver&#xff0c;以及chrome路径 对应这篇文章&#xff0c;可以点击查看&#xff0c;详情 from selenium import webdriverdef get_driver():# 获取配置对象option webdriver.ChromeOptions()option.add_experimental_option("de…...

高等代数笔记—线性变换

latex花体字母与花体数字 https://blog.csdn.net/weixin_39589455/article/details/133846783 https://blog.csdn.net/orz_include/article/details/123645710线性变换 线性空间 V V V到自身的映射称为 V V V的一个变换&#xff0c;最基本的是线性变换。 定义&#xff1a;变换…...

Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统

Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统 需求 在实际生成操作过程中&#xff0c;一般会遇到物理服务器存在多块盘的情况。 安装过程中&#xff0c;磁盘的标签是随机分配的&#xff0c;并不是空间较小的盘&#xff0c;就会使用较小的磁盘标签 而需求往往需要…...

2024BaseCTF_week4_web上

继续&#xff01;冲冲冲 目录 圣钥之战1.0 nodejs 原型 原型链 原型链污染 回到题目 flag直接读取不就行了&#xff1f; 圣钥之战1.0 from flask import Flask,request import jsonapp Flask(__name__)def merge(src, dst):for k, v in src.items():if hasattr(dst, __geti…...

大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡

大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡 背景 前端开发接口请求&#xff0c;调试&#xff0c;联调&#xff0c;接入数据&#xff0c;前端必不可少工具&#xff0c;postman是一个非常好…...

内网穿透的应用-Ubuntu本地Docker搭建pichome文件管理系统打造个人云相册

文章目录 前言1.关于pichome2.本地部署pichome3.简单使用pichome4. 安装内网穿透5.配置pichome公网地址6. 配置固定公网地址 前言 你是不是也经常遇到这样的尴尬&#xff1a;手机、电脑里堆满了照片和视频&#xff0c;想找一张特定的图片时却像在大海捞针一样无从下手&#xf…...

深度学习之神经网络框架搭建及模型优化

神经网络框架搭建及模型优化 目录 神经网络框架搭建及模型优化1 数据及配置1.1 配置1.2 数据1.3 函数导入1.4 数据函数1.5 数据打包 2 神经网络框架搭建2.1 框架确认2.2 函数搭建2.3 框架上传 3 模型优化3.1 函数理解3.2 训练模型和测试模型代码 4 最终代码测试4.1 SGD优化算法…...

DeepSeek AI R1推理大模型API集成文档

DeepSeek AI R1推理大模型API集成文档 引言 随着自然语言处理技术的飞速发展&#xff0c;大语言模型在各行各业的应用日益广泛。DeepSeek R1作为一款高性能、开源的大语言模型&#xff0c;凭借其强大的文本生成能力、高效的推理性能和灵活的接口设计&#xff0c;吸引了大量开发…...

怎麼使用靜態住宅IP進行多社媒帳號管理

隨著社交媒體平臺的多樣化&#xff0c;很多人發現一個社媒帳號已經無法滿足需求。以下是幾個常見場景&#xff1a; 企業需求&#xff1a;企業可能需要在不同平臺上運營多個品牌帳號&#xff0c;為每個市場地區單獨設立帳號。個人需求&#xff1a;一些自由職業者或內容創作者可…...

【Elasticsearch】Bucket Selector Aggregation

Elasticsearch 的Bucket Selector Aggregation是一种强大的管道聚合功能&#xff0c;用于根据条件过滤聚合结果中的桶&#xff08;buckets&#xff09;。它允许用户通过编写脚本来动态决定哪些桶应该被保留&#xff0c;哪些应该被过滤掉。以下是对Bucket Selector Aggregation的…...

CEF132 编译指南 MacOS 篇 - 启程:认识 CEF (一)

1. 引言 在当今的软件开发领域&#xff0c;将 Web 技术融入桌面应用程序已成为一种趋势。开发者们寻求一种方式&#xff0c;既能充分利用原生应用的性能&#xff0c;又能享受 Web 开发带来的高效和灵活性。Chromium Embedded Framework (CEF) 应运而生&#xff0c;它是一个基于…...

Python 操作 MongoDB 教程

一、引言 在当今数字化时代&#xff0c;数据的存储和管理至关重要。传统的关系型数据库在处理一些复杂场景时可能会显得力不从心&#xff0c;而 NoSQL 数据库应运而生。MongoDB 作为一款开源的、面向文档的 NoSQL 数据库&#xff0c;凭借其高性能、高可扩展性和灵活的数据模型…...

长安汽车发布“北斗天枢2.0”计划,深蓝汽车普及全民智驾

2月9日&#xff0c;长安汽车智能化战略“北斗天枢2.0”计划暨深蓝汽车全场景智能驾驶解决方案发布会在重庆盛大召开。此次发布会标志着长安汽车正式迈入智能化战略的新纪元&#xff0c;携手众多“中国智驾合伙人”&#xff0c;共同开启全民智驾元年。 发布会上&#xff0c;长安…...

SpringBoot速成(七)注册实战P2-P4

1.创建 数据库创建 依赖引入 <!-- mybatis起步依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency> <…...

大语言模型RAG,transformer

1、RAG技术流总结 第一张图是比较经典的RAG知识图谱&#xff0c;第二张图是更加详细扎实的介绍图。 1.1 索引 坦白来说这部分的技术并不是大模型领域的&#xff0c;更像是之前技术在大模型领域的应用&#xff1b;早在2019年我就做过faiss部分的尝试&#xff0c;彼时索引技术已…...

Crowdin 在线本地化平台调用硅基流动AI预翻译

平台介绍 硅基流动&#xff08;AI服务平台&#xff09; 官网&#xff1a;https://siliconflow.cn/zh-cn/ 官方介绍 我主要使用&#xff1a;云服务平台 SilliconCloud 此平台已经将热门的开源大语言模型部署&#xff0c;花钱买额度&#xff0c;就能使用 API 最近有上线 Deep…...

第5章 数据库系统(选择|案例|论文)(重点★★★★★)

5.1 数据库管理系统1 数据库是长期存储在计算机内的、有组织的、可共享的数据集合&#xff0c;数据库系统是指在计算机信息系统中引入数据库后的系统&#xff0c;一般由数据库、数据库管理系统 (DataBaseManagement System&#xff0c;DBMS)、应用系统、数据库管理员(DataBase…...

linux部署node服务

1、安装nvm管理node版本 # 下载、解压到指定目录 wget https://github.com/nvm-sh/nvm/archive/refs/tags/v0.39.1.tar.gz tar -zxvf nvm-0.39.0.tar.gz -C /opt/nvm # 配置环境 vim ~/.bashrc~&#xff1a;这是一个路径简写符号&#xff0c;代表当前用户的主目录。在大多数 …...

【AI赋能】蓝耘智算平台实战指南:3步构建企业级DeepSeek智能助手

蓝耘智算平台实战指南&#xff1a;3步构建企业级DeepSeek智能助手 引言&#xff1a;AI大模型时代的算力革命 在2025年全球AI技术峰会上&#xff0c;DeepSeek-R1凭借其开源架构与实时推理能力&#xff0c;成为首个通过图灵测试的中文大模型。该模型在语言理解、跨模态交互等维…...

hyperf知识问题汇总

1、简单说下 hyperf&#xff08;什么是 hyperf&#xff09; 答&#xff1a;hyperf 是一个依赖swoole扩展的 php 开源开发框架&#xff0c;它由黄朝辉团队设计创建维护&#xff0c;具备简洁而强大的组件和超强的并发性能&#xff0c;而且还支持微服务架构&#xff0c;例如&…...