首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
v2ray节点搭建
1,064 阅读
2
软件添加id功能按钮
1,003 阅读
3
QQ扫码无法登录的解决方案
946 阅读
4
网易云音乐歌单ID获取教程
797 阅读
5
js逆向xhs
745 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
rust
flutter
esp32c3
springboot
安卓
linux
vue
dart
设计模式
docker
joe
快捷键
git
fish shell
maven
redis
netty
groovy
js
尽意
累计撰写
113
篇文章
累计收到
41
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
97
篇与
的结果
2025-04-27
rust开发esp32c3驱动oled屏幕
使用的是 I2C SSD1306 0.96寸的OLED屏幕1.在Cargo.toml中添加图形库依赖# 处理ssd1306屏幕 ssd1306 = {version = "0.10.0",features = ["graphics"]} embedded-graphics = "0.8.1"完整配置 Cargo.toml[package] name = "esp32c3-oled-demo" version = "0.1.0" authors = ["suxii <m@suxii.cn>"] edition = "2021" resolver = "2" rust-version = "1.77" [[bin]] name = "esp32c3-oled-demo" harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors [features] default = [] experimental = ["esp-idf-svc/experimental"] [dependencies] log = "0.4" esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync","experimental","std"] } futures = "0.3.31" anyhow = "1.0.98" esp-idf-hal = "0.45.2" # 处理ssd1306屏幕 ssd1306 = {version = "0.10.0",features = ["graphics"]} embedded-graphics = "0.8.1" [build-dependencies] embuild = "0.33" 2.在main.rs中编写rust代码use esp_idf_hal::{ delay::FreeRtos, i2c::*, peripherals::Peripherals, prelude::*, }; use embedded_graphics::{ mono_font::{ascii::FONT_6X10, MonoTextStyle}, pixelcolor::BinaryColor, prelude::*, primitives::{Circle, Line, PrimitiveStyle, Rectangle}, text::Text }; use ssd1306::{I2CDisplayInterface, Ssd1306, prelude::*, size::DisplaySize128x64}; fn main() -> anyhow::Result<()> { esp_idf_hal::sys::link_patches(); // 初始化外设 let peripherals = Peripherals::take()?; // 配置I2C let i2c = peripherals.i2c0; let sda = peripherals.pins.gpio5; let scl = peripherals.pins.gpio6; let config = I2cConfig::new().baudrate(400.kHz().into()); let i2c = I2cDriver::new(i2c, sda, scl, &config)?; // 创建SSD1306接口 let interface = I2CDisplayInterface::new(i2c); let mut display = Ssd1306::new( interface, DisplaySize128x64, DisplayRotation::Rotate0 ).into_buffered_graphics_mode(); // 初始化显示屏 display.init().expect("SSD1306 init failed"); display.flush().expect("Failed to flush display"); // 创建图形样式 let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); let line_style = PrimitiveStyle::with_stroke(BinaryColor::On, 1); let mut run_x = 64; loop { // 清空屏幕 display.clear(BinaryColor::Off).unwrap(); // 绘制边框 Rectangle::new(Point::new(0, 0), Size::new(128, 64)) .into_styled(line_style) .draw(&mut display).unwrap(); // 绘制文本 Text::new("Hello Rust!", Point::new(10, 15), text_style) .draw(&mut display).unwrap(); // 绘制直线 Line::new(Point::new(10, 25), Point::new(118, 25)) .into_styled(line_style) .draw(&mut display).unwrap(); // 绘制圆形 if run_x > 128 { run_x = 0 } run_x+=10; Circle::new(Point::new(run_x, 40), 20) .into_styled(line_style) .draw(&mut display).unwrap(); // 更新显示 display.flush().expect("Failed to flush display"); // 间隔2秒 FreeRtos::delay_ms(2000); } }3.接线 SSD1306SDA -> io05SCL -> io06VCC -> 5vGND -> GND4.效果展示
2025年04月27日
141 阅读
0 评论
1 点赞
Rust 与 Kotlin:优雅的数据传输与多态序列化实践
在现代软件开发中,尤其是在系统编程和移动应用领域,实现不同语言之间的数据交换至关重要。Rust 和 Kotlin 都以其高性能和安全性著称,提供了强大的多态序列化机制,能够确保数据结构在不同语言间的一致性和可维护性。本文将通过一个示例,展示如何在 Rust 和 Kotlin 中定义和处理多态消息,确保它们之间的无缝互操作。定义消息结构我们希望构建一个多态消息系统,包含两种类型的消息:LedMessage:控制 LED 的整数值。TextMessage:发送一条文本消息。Rust 实现Rust 使用 serde 库进行序列化和反序列化。通过使用 #[serde(tag = "type")] 属性,我们可以根据 type 字段区分不同的消息类型。use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type")] enum Message { #[serde(rename = "led")] Led(LedMessage), #[serde(rename = "text")] Text(TextMessage), #[serde(other)] Unknown, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct LedMessage { value: i32, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct TextMessage { text: String, } impl Message { fn to_json(&self) -> serde_json::Result<String> { serde_json::to_string(self) } fn from_str(src: &str) -> serde_json::Result<Self> { serde_json::from_str(src) } } fn test() { let led_message = Message::Led(LedMessage { value: 33 }); let encoded = led_message.to_json().unwrap(); println!("{}", encoded); match Message::from_str("{\"text\":\"hello text\",\"type\":\"text\"}").unwrap() { Message::Led(led_message) => { println!("收到 LedMessage:{}", led_message.value) } Message::Text(text_message) => { println!("收到 TextMessage:{}", text_message.text) } Message::Unknown => { println!("未知的消息类型") } } }在这个实现中,type 字段用于区分不同的消息类型,serde 会根据该字段自动选择合适的枚举变体进行反序列化。Kotlin 实现Kotlin 使用 kotlinx.serialization 库处理多态序列化。通过自定义序列化器,我们可以根据 type 字段动态选择合适的反序列化器。import kotlinx.serialization.* import kotlinx.serialization.json.* object MessageSerializer : JsonContentPolymorphicSerializer<Message>(Message::class) { override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Message> { val type = element.jsonObject["type"]!!.jsonPrimitive.content return when (type) { "led" -> Message.LedMessage.serializer() "text" -> Message.TextMessage.serializer() else -> throw SerializationException("未知类型:$type") } } } @Serializable(with = MessageSerializer::class) sealed class Message { abstract val type: String fun toJson(): String { return json.encodeToString(Message.serializer(), this) } companion object { private val json = Json { ignoreUnknownKeys = false encodeDefaults = true } fun fromStr(src: String): Message { return json.decodeFromString<Message>(src) } } @Serializable data class LedMessage(val value: Int, override val type: String = "led") : Message() @Serializable data class TextMessage(val text: String, override val type: String = "text") : Message() }在这个实现中,MessageSerializer 会根据 JSON 中的 type 字段动态选择合适的反序列化器,从而实现多态反序列化。Rust 与 Kotlin 的互操作性为了实现 Rust 与 Kotlin 之间的无缝通信,我们可以在 Rust 中将 Message 枚举序列化为 JSON,然后在 Kotlin 中反序列化,或者反向操作。Rust 到 JSONlet led_message = Message::Led(LedMessage { value: 33 }); let json = led_message.to_json().unwrap(); println!("{}", json);输出:{"type":"led","value":33}Kotlin 从 JSONval json = """{"type":"led","value":33}""" val message = Message.fromStr(json) println(message)输出:LedMessage(value=33, type=led)通过这种方式,Rust 和 Kotlin 可以共享相同的数据结构,确保数据的一致性和类型安全。总结通过利用 Rust 的 serde 和 Kotlin 的 kotlinx.serialization,我们可以实现优雅且高效的多态序列化。这种方式不仅确保了类型安全,还促进了不同语言之间的平滑数据交换。采用这些序列化技术,可以增强应用程序的互操作性,使其更加健壮和可维护。
2025年04月26日
137 阅读
0 评论
1 点赞
安卓开发引入hilt实现依赖注入
1.在根目录下的build.gradle添加buildscript { dependencies { classpath 'com.google.dagger:hilt-android-gradle-plugin:2.48' } } plugins { ... id 'com.google.dagger.hilt.android' version '2.43.2' apply false } 2.在app目录下的build.gradle文件添加plugins { ... // 使用hilt id 'kotlin-kapt' // 添加 kapt 支持 id 'dagger.hilt.android.plugin' // 添加 Hilt 插件 } 引入依赖dependencies { ... // Hilt 核心依赖 implementation "com.google.dagger:hilt-android:2.48" kapt "com.google.dagger:hilt-android-compiler:2.48" // 如果使用 Compose,还需要添加 Hilt 的 Compose 扩展支持 implementation "androidx.hilt:hilt-navigation-compose:1.0.0"3.在项目中简单使用
2025年04月24日
130 阅读
0 评论
1 点赞
2025-04-23
记录一下安卓编译报错(Execution failed for task ':app:checkDebugAarMetadata')
报错信息:这两个地方显示依赖版本过高,去toml文件找到对应的版本 1. Dependency 'androidx.activity:activity:1.10.1' requires libraries and applications that depend on it to compile against version 35 or later of the Android APIs. 2. Dependency 'androidx.activity:activity-compose:1.10.1' requires libraries and applications that depend on it to compile against version 35 or later of the Android APIs.解决方案将 coreKtx = "1.16.0" 改成 coreKtx = "1.13.1"activityCompose = "1.10.1" 改成 activityCompose = "1.9.0"下面是修改后的同步一下,重新编译,通过了
2025年04月23日
172 阅读
0 评论
1 点赞
flutter使用扩展方法提升开发效率
一、什么是扩展方法?扩展方法是Dart 2.7版本引入的特性,它允许开发者在不修改现有类代码的前提下,为类添加新的功能。这一特性不仅方便了代码的扩展,而且使得业务逻辑的表达更加直观。扩展方法的核心特点无侵入性:你可以为第三方库或系统类添加新功能,而无需修改原始代码。代码简洁:将常用的逻辑封装成方法,并支持链式调用。语义清晰:可以使API的调用更加符合业务直觉,提升代码的可读性。语法示例:通过以下示例,我们为 String 类型添加一个 isValidEmail 方法,用于验证邮箱格式:// 为String添加扩展方法 extension StringExt on String { bool get isValidEmail => RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this); } // 使用扩展方法 final email = 'user@example.com'; if (email.isValidEmail) { // 校验通过 }二、Flutter生态中的经典案例在Flutter中,很多库通过扩展方法,使得代码的编写更加简洁与优雅。我们来看几个经典的应用场景:1. 状态管理:Provider的context.read与context.watchprovider库通过扩展方法,简化了获取和监听状态的过程。传统的方式需要在 BuildContext 中通过 Provider.of 方法获取模型:// 传统方式 final model = Provider.of<CounterModel>(context, listen: false);而使用扩展方法之后,你可以像这样更加简洁地获取模型:// 使用扩展方法 final model = context.read<CounterModel>();扩展方法实现原理:extension ReadContext on BuildContext { T read<T>() => Provider.of<T>(this, listen: false); } extension WatchContext on BuildContext { T watch<T>() => Provider.of<T>(this); }read<T>() 方法用于获取 Provider 中的状态,并且不会监听状态变化;而 watch<T>() 则会在状态变化时自动重建依赖该状态的UI组件。2. 路由导航:go_router的context.go()go_router 库通过扩展方法简化了路由跳转的操作。在传统的 Navigator.push 方式下,我们需要手动构建 MaterialPageRoute,如下所示:// 传统Navigator跳转 Navigator.push(context, MaterialPageRoute(builder: (_) => DetailPage()));而使用 go_router 提供的扩展方法后,路由跳转变得更加直观和简洁:// 使用go_router扩展方法 context.go('/detail/123');扩展方法实现原理:extension GoRouterExtension on BuildContext { void go(String location) => GoRouter.of(this).go(location); }通过这种方式,go() 方法使得路由跳转代码更加简洁,并且避免了冗长的 Navigator.push 代码。3. MaterialApp.router:命名构造函数虽然 MaterialApp.router 看似像一个扩展方法,但它其实是一个命名构造函数,用于配置 Flutter 项目的路由:MaterialApp.router( routeInformationParser: _router.routeInformationParser, routerDelegate: _router.routerDelegate, )它的作用是通过 Router 控制整个应用的路由导航,而不像传统的 Navigator 那样基于堆栈来进行管理。三、自定义扩展方法实战场景1:屏幕尺寸快速获取在Flutter中,我们常常需要根据屏幕的宽度或高度来决定布局。通过扩展方法,我们可以快速获取屏幕的相关信息,避免多次调用 MediaQuery。extension ScreenSizeExt on BuildContext { double get width => MediaQuery.of(this).size.width; double get height => MediaQuery.of(this).size.height; bool get isMobile => width < 600; } // 使用 final screenWidth = context.width; if (context.isMobile) { // 移动端布局 }在这个例子中,我们通过 context.width 获取屏幕宽度,并且通过 context.isMobile 判断当前设备是否是移动端。场景2:日期格式化日期格式化是一个常见的需求。我们可以通过扩展方法为 DateTime 类型添加格式化功能:extension DateFormatExt on DateTime { String get yyyyMMdd => DateFormat('yyyy-MM-dd').format(this); } // 使用 final date = DateTime.now(); print(date.yyyyMMdd); // 输出:2023-09-15这个扩展方法让我们能够直接使用 yyyyMMdd 来获取日期的格式化字符串。场景3:Widget快捷操作在Flutter中,Widget 的布局通常需要做一些基础操作,比如加 Padding、Center 等。通过扩展方法,我们可以为 Widget 类型添加这些常用的操作,使得代码更加简洁:extension WidgetExt on Widget { Widget paddingAll(double value) => Padding( padding: EdgeInsets.all(value), child: this, ); Widget get center => Center(child: this); } // 使用 Text('Hello').paddingAll(8).center;这里,我们为 Widget 添加了 paddingAll 和 center 方法,使得 Text('Hello') 能够轻松应用 Padding 和 Center 布局。四、扩展方法的最佳实践1. 命名规范使用 Ext 后缀:ScreenSizeExt、DateFormatExt 等。命名要清晰:如 DateFormatExt,而不是 UtilityExt,使其作用更加明确。2. 作用域控制按功能分文件:如 context_ext.dart、string_ext.dart 等文件,避免文件过于庞大。按需导入:仅在需要的地方导入扩展文件,避免全局污染。3. 避免过度使用扩展方法的使用要有原则。虽然它能提高代码的简洁性,但过度使用可能导致代码可读性降低:适用场景:高频使用的工具方法。增强第三方库的API。统一的业务逻辑封装。不适用场景:复杂的业务逻辑(应封装为独立类)。需要覆盖原有方法的场景。五、注意事项导入要求:使用扩展方法时,需要确保导入相应的扩展文件。优先级:扩展方法的优先级低于原生方法,它不会覆盖现有方法。类型限定:扩展方法仅对指定类型有效,使用时要注意限定类型。空安全:在处理可空类型时,确保使用 on Type? 来避免空指针异常。extension NullableStringExt on String? { bool get isNullOrEmpty => this == null || this!.isEmpty; }
2025年04月03日
135 阅读
0 评论
2 点赞
1
2
3
4
...
20