Rust 跨平台-Android 和鸿蒙 OS
1. 安装 rustup
 
rustup 是 Rust 的安装和版本管理工具
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh 
该命令会安装 rusup 和最新的稳定版本的 Rust;包括:
-  
rustcRust 编译器,用于将 Rust 代码编译成可执行文件或库。 -  
cargoRust 的包管理器和构建工具,用于管理项目依赖、编译项目、运行测试等。 -  
rustfmt代码格式化工具,用于自动格式化 Rust 代码以符合官方风格指南。 -  
clippy静态分析工具,用于捕捉常见错误和改进代码质量。 -  
其他工具,如
rustdoc用于生成文档等。 
成功后控制台会输出:Rust is installed now. Great!
macOS 系统上需要安装:xcode-select --install
cargo 在开发中较为常用,算是打交道最多的工具之一
2. 标准库 Rust Standard Library
标准库是 Rust 编程语言的官方库,提供了一系列预先编写好的类型和函数,用来处理常见的任务,如:
-  
基本数据类型(比如
i32,u64,f32等)。 -  
集合类型(如
Vec<T>,HashMap<K, V>等)。 -  
输入/输出(I/O)操作,包括文件操作和网络编程。
 -  
线程和并发编程工具。
 -  
其他有用的工具,如字符串处理、日期和时间操作等。
 
渠道
通常情况下安装 rustup 的时候,标准库就已经安装到本地;但是 rust 有几种发布渠道,用于提供不同稳定程度的 Rust 版本,Rust 的三个主要发布渠道是:
-  
Stable(稳定版):这是大多数用户推荐使用的版本。它每六周发布一次,提供最新的功能和改进,但只包括那些经过充分测试和认为稳定的特性。
 -  
Beta(测试版):这个版本比 Stable 新,但可能包含一些即将纳入下一个 Stable 版本的特性和改进。它主要用于测试即将发布的功能,以确保它们在正式成为稳定版之前没有问题。
 -  
Nightly(每夜构建版):这是最前沿的版本,包括了所有最新开发的特性。这些特性可能未完全稳定或待评估,因此这个版本主要用于实验和评估最新的语言改进。Nightly 版本,顾名思义,每夜更新一次,包括最新的代码提交。
 
安装
-  
列出已安装的版本
 
rustup toolchain list 
-  
安装新的版本
 
rustup toolchain install beta 
或者
rustup toolchain install nightly 
切换版本
切换全局(即默认)Rust 版本,使用rustup default命令:
rustup default stable
rustup default beta
rustup default nightly 
这些命令会将你的系统默认 Rust 版本切换为相应的版本。
为特定项目切换版本
如果你只想为特定的项目切换 Rust 版本,而不影响全局设置,可以在项目目录内使用以下命令设置目录级别的默认版本:
rustup override set stable
rustup override set beta
rustup override set nightly 
补装标准库源码
rustup component add rust-src 
每一个 toolchain 都有自己的源码
建议安装 stable 和 nightly 的源码,因为只有 nightly 版本支持编译鸿蒙系统
如果不安装后续鸿蒙 OS 下编译会报错,根据提示安装也行
为特定目标平台编译代码
在 stable 下,rust 支持 android 平台的编译,通过 rustup target list |grep android 可以查看支持的所有平台架构
% rustup target list |grep android                                                                                                                                                    24-03-19 - 15:46:34
aarch64-linux-android (installed)
arm-linux-androideabi (installed)
armv7-linux-androideabi (installed)
i686-linux-android (installed)
thumbv7neon-linux-androideabi (installed)
x86_64-linux-android (installed) 
如果已安装,后面会有 (installed) 标识;建议一次性都安装上:
rustup target add aarch64-linux-android arm-linux-androideabi armv7-linux-androideabi i686-linux-android thumbv7neon-linux-androideabi x86_64-linux-android 
鸿蒙 OS 下需要切换到 nightly,通过 rustup target list |grep ohos 可以查看支持的所有平台架构:
% rustup target list |grep ohos                                                         
aarch64-unknown-linux-ohos (installed)
armv7-unknown-linux-ohos (installed)
x86_64-unknown-linux-ohos (installed) 
同样,建议一次性都安装上
3. 创建 Rust Library 工程
使用命令行创建:
cargo new demo --lib 
或者使用 IDE,推荐使用 Jetbrains 的 RustRover

此时目录结构如下:
demo
├── Cargo.toml
└── src└── lib.rs 
Cargo.toml 的配置
[lib]
[lib]
crate-type = ["cdylib"] 
crate-type属性用于指定编译目标类型。这些类型决定了编译器会如何编译你的代码。以下是一些常见的crate-type值及其区别:
1. bin
-  
描述:一个可执行的二进制文件。
 -  
使用场景:当你想要创建一个可以直接运行的程序时,使用此类型。大多数应用程序都是以
bin类型编译的。 
2. lib
-  
描述:一个库文件,可以被其他 Rust 包作为依赖使用。
 -  
使用场景:如果你正在开发一个提供函数、类型或特性给其他包使用的库,应选择此类型。
 
3. rlib
-  
描述:Rust 编译的库文件,包含元数据和符号,供后续的 Rust 编译阶段使用。
 -  
使用场景:当你想要编译一个 Rust 库供其他 Rust 项目使用,并期望进行链接和代码生成优化时。
 
4. dylib
-  
描述:一个动态链接库(DLL),可以在运行时被 Rust 或其他语言的应用程序动态链接。
 -  
使用场景:当你想要创建一个可以被多个程序共享的库,或者当你需要和其他使用动态链接的语言互操作时。
 
5. cdylib
-  
描述:一个为 C 语言接口定制的动态链接库。它移除了 Rust 特有的元数据,只保留了可以从 C 或其他语言调用的符号。
 -  
使用场景:当你开发一个 Rust 库,希望能够被 C 或其他语言作为动态链接库使用时。这是创建跨语言共享库的常见方式。
 
6. staticlib
-  
描述:静态库(
.a文件),可以被 C 语言或其他语言的应用程序在编译时静态链接。 -  
使用场景:如果你想要创建一个可以被其他语言静态链接的库,或希望你的 Rust 代码被编译进一个单独的二进制文件,而不依赖于 Rust 的运行时或其他动态库。
 
7. proc-macro
-  
描述:一个过程宏库,用于创建自定义
#[derive]宏或其他类型的宏。 -  
使用场景:当你想要创建新的宏来扩展 Rust 语法,比如自定义派生属性或宏指令时。
 
[dependencies] 和 [features]
由于需要区分 android 和 ohos 两个平台的特定库,所以有一些依赖库需要配置为可选的,然后使用 cargo 构建的时候添加 --features 参数来分别进行交叉编译
对于 android 平台,需要引入 jni 库,来和 java/kotlin 互相调用
rust和node互相调用可以使用node-bindgen,但遗憾的是,node-bindgen并不兼容鸿蒙系统;不过已经有人基于node-bindgen兼容了 ohos:https://crates.io/crates/ohos-node-bindgen对于
ohos平台,需要引入ohos-node-bindgen库,来和node通信;由于ohos-node-bindgen依赖socket2,然而socket2在ohos下有bug,所以这里需要使用https://github.com/stuartZhang/socket2.git来替换ohos-node-bindgen内部依赖的socket2版本
最终配置如下
[features]
default = ["android"]
android = ["dep:jni", "dep:android_logger"]
ohos = ["dep:ohos-node-bindgen", "dep:socket2"][dependencies]
jni = { version = "0.19.0", optional = true }
android_logger = { version = "0.13.3", optional = true }
ohos-node-bindgen = { version = "6.0.3", optional = true }
socket2 = { version = "0.4.10", optional = true }
dashmap = "5.5.3"
threadpool = "1.8.1"
log = "0.4.21"[patch.crates-io]
socket2 = { version = "0.4.10", git = "https://github.com/stuartZhang/socket2.git", branch = "v0.4.x" } 
也就是说:
-  
dashmap、threadpool和log是所有平台下都参与编译的库 -  
android单独编译:jni和android_logger -  
ohos单独编译:ohos-node-bindgen和socket2 -  
另外,
features的默认值为android 
编写代码 - lib.rs
由于存在不同的 features,所以对于 android:
#[cfg(feature = "android")]
#[no_mangle]
pub extern "system" fn Java_com_haier_uhome_uplus_hook_monitor_app_NativeLib_hello(env: JNIEnv,_class: JClass,
) -> jstring {// 将 Rust 字符串转换为 JNI 字符串let result = env.new_string("Hello from Rust!").expect("Couldn't create Java string!");// 返回结果result.into_inner()
} 
#[cfg(feature = "android")]:与上述 features 对应
#[no_mangle] 则是禁用驼峰警告
对于 ohos:
#[cfg(feature = "ohos")]
#[ohos_node_bindgen]
pub extern "C" fn add(l: i32, r: i32) -> i32 {l + r
} 
#[cfg(feature = "ohos")]:与上述 features 对应
#[ohos_node_bindgen] 则是标识 add 函数可以被 node 端调用
node-bindgen 的大致原理如下:
1. FFI(外部函数接口)
Node.js 的原生模块基于 C++ 和 Node.js 的 N-API(原生 API),N-API 提供了一套与 V8 引擎解耦的接口,使原生模块在 Node.js 版本升级时保持兼容。
node-bindgen底层利用 Rust 的外部函数接口(FFI)能力,通过这些接口与 Node.js 通信。Rust 的 FFI 功能允许其调用 C 语言 API。因此,
node-bindgen实际上是通过 Rust 的 FFI 调用 Node.js 的 N-API 来创建和管理 JavaScript 值,以及执行与 JavaScript 环境的交互。2. 宏和属性
node-bindgen提供了一系列宏(例如#[node_bindgen]),这些宏在编译时自动生成将 Rust 函数暴露为 Node.js 可调用函数的胶水代码。这个过程包括自动生成用于参数转换和返回值处理的代码,使 Rust 函数能够直接接收来自 JavaScript 的参数并返回可以直接在 JavaScript 中使用的结果。3. 内存管理
Rust 和 JavaScript 之间的内存管理是
node-bindgen的关键部分。Rust 有自己的内存管理规则,主要基于所有权和生命周期,而 JavaScript 的内存则由垃圾收集器自动管理。node-bindgen必须确保在这两种内存管理模型之间正确地桥接,包括处理 Rust 中的数据所有权转移和确保 JavaScript 对象在需要时保持存活。4. 异步操作
Node.js 广泛使用异步操作,而 Rust 也有强大的异步支持。
node-bindgen支持将 Rust 的异步操作暴露给 Node.js。这通过将 Rust 的Future转换为 Node.js 的Promise来实现。node-bindgen会自动处理这种转换,允许开发者以 Promise 的形式在 JavaScript 中接收 Rust 异步操作的结果。5. 类型转换
node-bindgen自动处理 Rust 类型和 JavaScript 类型之间的转换。对于简单类型(如数字和字符串),这通常是直接的。但对于复杂类型(如结构体或枚举),node-bindgen生成的代码会负责序列化和反序列化操作,确保两种语言之间可以无缝交换复杂数据结构。总结
node-bindgen利用 Rust 的 FFI 能力、宏系统、强类型系统和异步特性,提供了一种高效、类型安全的方式来将 Rust 代码与 Node.js 集成。它自动处理大部分繁琐的胶水代码编写工作,使得 Rust 和 Node.js 之间的交互变得更加简单直接。这样的设计允许开发者专注于实现应用逻辑,而无需深入底层的语言绑定细节。理解颇为浅陋,如有任何问题可私 1239604859@qq.com 讨论
编译 - android 平台的产物
官方提供了 cargo-ndk 工具,它简化了为 Android 使用 Rust 编写原生代码库(.so 文件)的过程。
-  
下载安卓 NDK,并配置到环境变量
 
export ANDROID_HOME=$HOME/ssd/Android/sdk
PATH="$ANDROID_HOME/ndk-bundle:$PATH"
export PATH 
-  
安装 cargo-ndk
 
cargo install cargo-ndk 
-  
使用
cargo-ndk构建你的项目 
cargo ndk -t armv7-linux-androideabi -t aarch64-linux-android -o ../../MonitorTestClient/app/src/main/jniLibs build --release 
-  
参数解释
-  
-t或--target:指定目标架构 -  
-o或--output:指定输出目录,这里的目录会用于存放编译生成的.so文件 -  
build:是cargo的子命令,用于编译项目,会传递它以及任何附加参数给cargo build 
 -  
 
编译 - ohos 平台的产物
官方没有为鸿蒙系统提供类似cargo-ndk的工具,需要手动配置编译参数
1. 首先切换到 nightly 渠道
rustup override set nightly 
2. 配置环境变量:
# huawei
export OHOS_HOME=$HOME/ssd/huawei/sdk
export OHOS_API_V=9
export OHOS_CORE_V=3.1.0
export OH_NDK_ROOT=$OHOS_HOME/openharmony/$OHOS_API_V/native
PATH="$OHOS_HOME/hmscore/$OHOS_CORE_V/toolchains:$PATH"
export PATH 
单独配置 OHOS_API_V 的好处是如果华为更新了 Native SDK,可以更方便的动态切换
3. 创建 ohos 对应 target 的可执行脚本,例如和config.toml中 [target.aarch64-unknown-linux-ohos] 对应
-  
创建位置:
~/.cargo -  
aarch64-unknown-linux-ohos-clang.sh
 
#!/bin/sh
. $HOME/.bash_profile
exec $OH_NDK_ROOT/llvm/bin/clang \-target aarch64-linux-ohos \--sysroot=$OH_NDK_ROOT/sysroot \-D__MUSL__ \"$@" 
-  
armv7-unknown-linux-ohos-clang.sh
 
#!/bin/sh
. $HOME/.bash_profile
exec $OH_NDK_ROOT/llvm/bin/clang \-target arm-linux-ohos \--sysroot=$OH_NDK_ROOT/sysroot \-D__MUSL__ \-march=armv7-a \-mfloat-abi=softfp \-mtune=generic-armv7-a \-mthumb \"$@" 
-  
x86_64-unknown-linux-ohos-clang.sh
 
#!/bin/sh
. $HOME/.bash_profile
exec $OH_NDK_ROOT/llvm/bin/clang \-target x86_64-linux-ohos \--sysroot=$OH_NDK_ROOT/sysroot \-D__MUSL__ \"$@" 
-  
. $HOME/.bash_profile根据实际情况进行修改,只要能拿到$OH_NDK_ROOT即可 
4. 通用配置:config.toml
-  
创建位置:
~/.cargo 
# 鸿蒙编译工具链-目前只能手动配置:
[target.aarch64-unknown-linux-ohos]
linker = ".cargo/aarch64-unknown-linux-ohos-clang.sh"[target.armv7-unknown-linux-ohos]
linker = ".cargo/armv7-unknown-linux-ohos-clang.sh"[target.x86_64-unknown-linux-ohos]
linker = ".cargo/x86_64-unknown-linux-ohos-clang.sh"# 会概率性地失败于exit code: 0xc0000005, STATUS_ACCESS_VIOLATION错误 - https://rustcc.cn/article?id=568d35d6-b782-49e9-b9b1-5d870d28f927
[profile.dev.package.compiler_builtins]
opt-level = 2[alias]
ohos-build = ["build", "-Zbuild-std", "--target=aarch64-unknown-linux-ohos", "--target=armv7-unknown-linux-ohos", "--target=x86_64-unknown-linux-ohos"] 
-  
[alias]作用是使得:cargo ohos-build --release等价于cargo build -Zbuild-std --target=aarch64-unknown-linux-ohos --target=armv7-unknown-linux-ohos --target=x86_64-unknown-linux-ohos --release -  
对于我们演示的 demo 工程,最终编译命令行如下
 
cargo ohos-build --release --features ohos 
 
4. Android 工程测试 rust 产物
把动态库拷贝到 app 模块中
src
├── androidTest
├── main
│   ├── jniLibs
│   │   ├── arm64-v8a
│   │   │   └── libdemo.so
│   │   └── armeabi-v7a
│   │       └── libdemo.so 
创建对应包名的单例
object NativeLib {init {System.loadLibrary("demo")}external fun hello(): Stringexternal fun mapTest()
} 
在 MainActivity 中调用
val nstr = NativeLib.hello()
Log.d(TAG, "onCreate: $nstr") 
2024-03-19 19:32:32.207 11941-11941 MainActivity             D  onCreate: Hello from Rust! 
 
5. ohos 工程测试 rust 产物
把动态库拷贝到 entry 模块中
entry
├── build-profile.json5
├── hvigorfile.ts
├── libs
│   ├── arm64-v8a
│   │   └── libdemo.so
│   └── armeabi-v7a
│       └── libdemo.so 
在 Index.ets 中
import hello from "libdemo.so"@Entry
@Component
struct Index {@State message: string = 'Hello World';build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)Button("计 算").fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {let sum = hello.add(3, 5);this.message = "3 + 5 = " + sum.toString();})}.width('100%')}.height('100%')}
} 
运行结果:
      
6. 团队介绍
「三翼鸟数字化技术平台-智家APP平台」通过持续迭代演进移动端一站式接入平台为三翼鸟APP、智家APP等多个APP提供基础运行框架、系统通用能力API、日志、网络访问、页面路由、动态化框架、UI组件库等移动端开发通用基础设施;通过Z·ONE平台为三翼鸟子领域提供项目管理和技术实践支撑能力,完成从代码托管、CI/CD系统、业务发布、线上实时监控等Devops与工程效能基础设施搭建。
相关文章:
Rust 跨平台-Android 和鸿蒙 OS
1. 安装 rustup rustup 是 Rust 的安装和版本管理工具 $ curl --proto https --tlsv1.2 https://sh.rustup.rs -sSf | sh 该命令会安装 rusup 和最新的稳定版本的 Rust;包括: rustc Rust 编译器,用于将 Rust 代码编译成可执行文件或库。 ca…...
Typora导出为Word
文章目录 一、场景二、安装1、网址2、解压并验证 三、配置四、重启Typora 一、场景 在使用Typora软件编辑文档时,我们可能需要将其导出为Word格式文件 当然我们可以直接在菜单里进行导出操作 文件-> 导出-> Word(.docx) 如果是第一次导出word文件࿰…...
数据库被后台爆破如何解决?
在数字化时代,数据库安全成为企业与组织不容忽视的关键环节。其中,“后台爆破”攻击,即通过自动化工具尝试大量的用户名和密码组合,以非法获取数据库访问权限,是常见的安全威胁之一。本文将详细介绍如何识别、防御并解…...
php7.4源码安装dbase7.1.1扩展
安装PHP开发工具 首先,你需要安装PHP开发工具,包括php-devel(或php7.4-devel,取决于你的PHP版本)和其他编译工具。 bash sudo yum install php7.4-devel gcc make 注意:如果你使用的是不同的PHP版本&#…...
OkHttp的源码解读1
介绍 OkHttp 是 Square 公司开源的一款高效的 HTTP 客户端,用于与服务器进行 HTTP 请求和响应。它具有高效的连接池、透明的 GZIP 压缩和响应缓存等功能,是 Android 开发中广泛使用的网络库。 本文将详细解读 OkHttp 的源码,包括其主要组件…...
08:结构体
结构体 1、为什么需要结构体2、如何定义结构体3、怎么使用结构体变量3.1、赋值和初始化3.2、结构体变量的输出 1、为什么需要结构体 为了表示一些复杂的事物,而普通的基本类型无法满足实际要求。什么叫结构体 把一些基本类型数据组合在一起形成的一个新的数据类型&…...
喜讯!安全狗荣获“2023年网络安全技术支撑优秀单位”称号
6月6日,由中共厦门市委网络安全和信息化委员会办公室(以下简称“厦门市委网信办”)主办的2023年网络安全技术支撑优秀单位颁奖仪式在厦门成功举行。 作为国内云原生安全领导厂商,安全狗受邀出席此次活动。 会上,安全狗…...
android里面json操作
1.读取assets下面xzhd/aikit/pck.json String json = null; try { InputStream is = activity.getAssets().open(aikitPathInData+"xzhd/aikit/pck.json"); int size = is.available(); byte[] buffer = new byte…...
MATLAB的.m文件与Python的.py文件:比较与互参
simulink MATLAB的.m文件与Python的.py文件:比较与互参相似之处**1. 基本结构****2. 执行逻辑****3. 可读性和维护性** 差异性**1. 语法特性****2. 性能和应用****3. 开发环境** 互相学习的可能性结论 MATLAB的.m文件与Python的.py文件:比较与互参 在编…...
武汉星起航:自运营团队精准把握亚马逊红利,引领跨境电商新潮流
在全球化的浪潮下,跨境电商行业蓬勃发展,为众多企业带来了前所未有的机遇。武汉星起航电子商务有限公司便是其中的佼佼者,其自运营团队凭借对亚马逊平台的深入了解和丰富的运营经验,成功抓住了亚马逊的流量红利,为公司…...
嵌入式计算器模块实现
嵌入式计算器模块规划 计算器混合算法解析 上面我们的算法理论已经完善, 我们只用给一个混合运算式, 计算器就可以帮助我们计算出结果. 但是存在一个痛点, 每次计算算式,都要重新编译程序, 所以我们想到了, 利用单片机, 读取用户输入的按键, 组成算式, 输入给机器, 这样我们就…...
tomcat定时重启
Tomcat定时重启(linux) 1. 编写脚本 在tomcat的bin目录下,使用vim restart.sh,编写restart.sh脚本,插入一下内容,最后并保存! #!/bin/bash# 初始化全局环境变量 . /etc/profilecd /usr/loca…...
构建LangChain应用程序的示例代码:48、如何使用非文本生成工具创建多模态代理
多模态输出:图像和文本 这个示例展示了如何使用非文本生成工具来创建多模态代理。 本例仅限于文本和图像输出,并使用UUID在工具和代理之间传输内容。 本例使用Steamship生成和存储生成的图像。生成的内容默认受到身份验证保护。 您可以在这里获取Ste…...
【笔记】记录一次全新的Java项目部署过程
记录一次全新的Java项目部署过程 环境:CentOS7一、初始环境准备 yum install wget -y yum install vim -y yum install net-tools -y mkdir /data mkdir /data/html mkdir /data/backend一、安装JDK 17 安装JDK17# 下载rpm wget https://download.oracle.com/java/17/latest/…...
达梦数据库系列—14. 表空间的备份和还原
目录 1、表空间备份 2、表空间还原 3、表空间恢复 4、增量还原恢复 1、表空间备份 表空间只能在联机状态下进行备份。 BACKUP TABLESPACE TBS BACKUPSET /dm/backup/dm_bak/ts_bak_01; 完全备份 BACKUP TABLESPACE TBS FULL BACKUPSET /dm/backup/dm_bak/ts_full_bak_01…...
奔驰G350升级原厂自适应悬挂系统有哪些作用
奔驰 G350 升级自适应悬挂系统后,可根据行车路况自动调整悬架高度和弹性,从而提升驾乘的舒适性和稳定性。 这套系统的具体功能包括: • 多种模式选择:一般有舒适、弯道、运动及越野等模式。例如,弯道模式在过弯时能为…...
一个启动脚本例子
一、全部代码 #!/bin/bash DATE$(date %Y%m%d)SOURCE"abc.jar" TARGET"backup/abc.jar.jew.$DATE"if [ -f "$SOURCE" ]; thencp "$SOURCE" "$TARGET" firm -f abc.jar mv abc_1.jar abc.jarpidNumps -ef | grep $SOURCE |…...
grpc学习golang版( 六、服务器流式传输 )
系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、前言二、定义proto文件三、拷贝任意文件进项目四、编写serve…...
ubuntu语音库ALSA报错具体原因
在ubuntu中使用pyaudio或portaudio时总会有下面的提示,不胜其烦。 ALSA lib pcm_dsnoop.c:612:(snd_pcm_dsnoop_open) unable to open slave ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_open) unable to open slave ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unkn…...
Java高级重点知识点-17-异常
文章目录 异常异常处理自定义异常 异常 指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。Java处 理异常的方式是中断处理。 异常体系 异常的根类是 java.lang.Throwable,,其下有两个子类:ja…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
