[{"content":" 噗噗订阅管理 - release-1.3.0\n底部查看更新内容\n准备开始慢慢更新 完成上一版开发后一直没管，想着就自己管理一下订阅，避免扣费。不过前两天看到微信数据显示有几十个用户陆续打开过小程序，既然还是能被人看见而且可能使用，那就继续更新。\n如果有任何建议，欢迎在小程序中的设置页面的反馈中提出。\nEcharts 之前草草地做了历史数据页面，这次整理了一下小程序中基础使用Echarts的步骤\n根据官方提供的模版项目把ec-canvas这个文件夹复制到自己项目中：https://github.com/ecomfe/echarts-for-weixin/tree/master/ec-canvas ec-canvas.js中有个isUseNewCanvas的变量，把默认值改成true，这样可以避免一个Canvas 2D警告 (Javascript项目跳过)Typescript项目需要给echarts.js添加类型声明文件，主要就是setOption这个方法。1 官方例子pages文件下随便找个例子抄一抄，完成自己页面中文件修改就可以展示图表了 index.json index.wxml index.js/ts pages/multiCharts下面展示了如何创建多个图表 pages/lazyLoad下面展示了如何懒加载图表，即可以先异步请求数据，再根据数据展示图表 推荐使用lazyLoad的方式来创建多个图标，充分利用selectComponent()的灵活性 更新内容 右上角按钮历史数据改成数据分析，并修改了数据分析页面的图表。 不过周末时间有限，只加了汇总数据，后续添加各月详情列表。 删除主页“各类别金额”部分，鸡肋。 更换底部添加按钮图标，统一风格。 修改添加页面图标选择的样式，统一风格。 图标选择popup内增加了类别选择，方便查找。 未来计划 Release-1.4.0 给订阅类别添加颜色，方便区分 在数据分析页面添加每月的详细数据列表 Release-2.0.0 离线数据，现在所有操作都是实时的，没有网络无法使用。 Release-2.1.0 添加新计划时能有更视觉化的操作方式，快速选择新计划的时间范围 类型定义代码\ndeclare module \u0026#34;echarts\u0026#34; { interface ECharts { setOption(option: EChartOption, opts?: EChartsOptionConfig): void; } interface EChartOption\u0026lt;TSeries = EChartOption.Series\u0026gt; {} namespace EChartOption { type Series = any; } interface EChartsOptionConfig { notMerge?: boolean | undefined; lazyUpdate?: boolean | undefined; silent?: boolean | undefined; } } \u0026#160;\u0026#x21a9;\u0026#xfe0e; ","permalink":"https://blog.congliu.dev/zh/posts/development/miniprogram/miniprogram-2/","summary":"\u003cblockquote\u003e\n\u003cp\u003e噗噗订阅管理 - release-1.3.0\u003cbr\u003e\n\u003ca href=\"/zh/posts/development/miniprogram/miniprogram-2/#%e6%9b%b4%e6%96%b0%e5%86%85%e5%ae%b9\"\u003e底部查看更新内容\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"准备开始慢慢更新\"\u003e准备开始慢慢更新\u003c/h2\u003e\n\u003cp\u003e完成上一版开发后一直没管，想着就自己管理一下订阅，避免扣费。不过前两天看到微信数据显示有几十个用户陆续打开过小程序，既然还是能被人看见而且可能使用，那就继续更新。\u003c/p\u003e\n\u003cp\u003e如果有任何建议，欢迎在小程序中的\u003ccode\u003e设置\u003c/code\u003e页面的\u003ccode\u003e反馈\u003c/code\u003e中提出。\u003c/p\u003e\n\u003ch2 id=\"echarts\"\u003eEcharts\u003c/h2\u003e\n\u003cp\u003e之前草草地做了历史数据页面，这次整理了一下小程序中基础使用\u003ccode\u003eEcharts\u003c/code\u003e的步骤\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e根据官方提供的模版项目把\u003ccode\u003eec-canvas\u003c/code\u003e这个文件夹复制到自己项目中：\u003ca href=\"https://github.com/ecomfe/echarts-for-weixin/tree/master/ec-canvas\"\u003ehttps://github.com/ecomfe/echarts-for-weixin/tree/master/ec-canvas\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eec-canvas.js\u003c/code\u003e中有个\u003ccode\u003eisUseNewCanvas\u003c/code\u003e的变量，把默认值改成true，这样可以避免一个Canvas 2D警告\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e(Javascript项目跳过)Typescript项目需要给\u003ccode\u003eecharts.js\u003c/code\u003e添加类型声明文件，主要就是\u003ccode\u003esetOption\u003c/code\u003e这个方法。\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003cli\u003e官方例子\u003ccode\u003epages\u003c/code\u003e文件下随便找个例子抄一抄，完成自己页面中文件修改就可以展示图表了\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eindex.json\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eindex.wxml\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eindex.js/ts\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epages/multiCharts\u003c/code\u003e下面展示了如何创建多个图表\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epages/lazyLoad\u003c/code\u003e下面展示了如何懒加载图表，即可以先异步请求数据，再根据数据展示图表\n\u003cul\u003e\n\u003cli\u003e推荐使用\u003ccode\u003elazyLoad\u003c/code\u003e的方式来创建多个图标，充分利用\u003ccode\u003eselectComponent()\u003c/code\u003e的灵活性\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"更新内容\"\u003e更新内容\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e右上角按钮\u003ccode\u003e历史数据\u003c/code\u003e改成\u003ccode\u003e数据分析\u003c/code\u003e，并修改了数据分析页面的图表。\n\u003cul\u003e\n\u003cli\u003e不过周末时间有限，只加了汇总数据，后续添加各月详情列表。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e删除主页“各类别金额”部分，鸡肋。\u003c/li\u003e\n\u003cli\u003e更换底部\u003ccode\u003e添加\u003c/code\u003e按钮图标，统一风格。\u003c/li\u003e\n\u003cli\u003e修改\u003ccode\u003e添加\u003c/code\u003e页面图标选择的样式，统一风格。\u003c/li\u003e\n\u003cli\u003e图标选择popup内增加了类别选择，方便查找。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"未来计划\"\u003e未来计划\u003c/h2\u003e\n\u003ch3 id=\"release-140\"\u003eRelease-1.4.0\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e给订阅类别添加颜色，方便区分\u003c/li\u003e\n\u003cli\u003e在\u003ccode\u003e数据分析\u003c/code\u003e页面添加每月的详细数据列表\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"release-200\"\u003eRelease-2.0.0\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e离线数据，现在所有操作都是实时的，没有网络无法使用。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"release-210\"\u003eRelease-2.1.0\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e添加新计划时能有更视觉化的操作方式，快速选择新计划的时间范围\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e类型定义代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-typescript\" data-lang=\"typescript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#66d9ef\"\u003edeclare\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodule\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e\u0026#34;echarts\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eECharts\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003esetOption\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eoption\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eEChartOption\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003eopts?\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eEChartsOptionConfig\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEChartOption\u003c/span\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003eTSeries\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEChartOption.Series\u003c/span\u003e\u0026gt; {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003enamespace\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEChartOption\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003etype\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eSeries\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eany\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEChartsOptionConfig\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003enotMerge?\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eundefined\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003elazyUpdate?\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eundefined\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003esilent?\u003c/span\u003e: \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eundefined\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e","title":"微信小程序开发 - 第二篇"},{"content":"又学一门新语言 在开始单片机开发学习之前，针对esp32上较常使用的几个开发工具和语言做了一点研究。\n工具主要有乐鑫官方提供的 ESP-IDF，以及 MicroPython 和 Arduino。\nESP-IDF是乐鑫官方提供的开发框架，支持C/C++，是最底层的开发方式，也是最灵活的。\nMicroPython是Python的一个子集，支持Python语言，是最简单的开发方式。\nArduino是一个开源的硬件开发平台，支持C/C++，简单而成熟，是最流行的开发方式。\n考虑到生态、性能以及拓展性。决定排除MicroPython。但是我之前一直从事软件开发，基本用的都是Java/Kotlin，Python，JavaScript等不需要考虑内存释放的高级语言，对于C/C++这种底层语言，还是上大学的时候学了一点，基本都忘记了。所以这次需要从底层语言开始重新学习。\n然后找到了esp-rs，发现ESP-IDF也支持Rust，而且最近Rust很火，大概看了一下语言特性，它的语法还是比较直观简洁的。无论C/C++还是Rust都要从头学，所以决定干脆学习Rust。\n有趣的特色 一些通用或比较简单的编程概念就不赘述了，可以通过查阅文档快速了解rust中的写法。不过Rust有一些很不同的语法和特性，这里简单列举一下。\n强大的枚举类型 - Enum https://kaisery.github.io/trpl-zh-cn/ch06-01-defining-an-enum.html\nRust的枚举类型是一种强大的数据类型，它可以包含多个不同的值，每个值可以是不同的类型。枚举类型可以用来表示一组相关的值，比如颜色、方向、状态等。\nenum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } 不一样的接口 - Trait https://kaisery.github.io/trpl-zh-cn/ch10-02-traits.html\nRust的Trait类似于其他高级语言中的接口，但是更加强大。Trait是一种抽象类型，它定义了一组方法，但是没有提供方法的具体实现。Trait可以被用来定义方法的签名，然后在具体的类型上实现这些方法。\nTrait可以被用来实现多态，可以在不同的类型上实现相同的Trait，然后通过Trait对象来调用这些方法。\npub trait Summary { fn summarize(\u0026amp;self) -\u0026gt; String; } pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, } impl Summary for NewsArticle { fn summarize(\u0026amp;self) -\u0026gt; String { format!(\u0026#34;{}, by {} ({})\u0026#34;, self.headline, self.author, self.location) } } 独特的内存管理 - 所有权 https://kaisery.github.io/trpl-zh-cn/ch04-01-what-is-ownership.html\nRust是一种系统编程语言，它的设计目标是提供一种安全、并发、实用的编程语言。\n除了一些基本语法的不同外，Rust最大的特点就是不一样的内存控制机制。通过所有权系统，能够最大程度在编译期间检查内存安全问题，避免了一些常见的内存错误，比如空指针、野指针、内存泄漏等。\nRust的内存管理有三个基本规则：\n每一个值都有一个变量，这个变量被称为这个值的所有者。 一个值的所有者在离开作用域时，这个值将被销毁。 一个值的所有者可以将这个值的所有权转移给另一个变量。 fn main() { let s1 = String::from(\u0026#34;hello\u0026#34;); let len = calculate_length(\u0026amp;s1); println!(\u0026#34;The length of \u0026#39;{s1}\u0026#39; is {len}.\u0026#34;); } fn calculate_length(s: \u0026amp;String) -\u0026gt; usize { // s is a reference to a String s.len() } // Here, s goes out of scope. But because it does not have ownership of what // it refers to, nothing happens. 无需垃圾回收 - 生命周期 https://kaisery.github.io/trpl-zh-cn/ch10-03-lifetime-syntax.html\nRust没有垃圾回收，但是有生命周期。生命周期是一种编译时的检查机制，用来确保引用的有效性。生命周期是一种标记，用来指示引用的有效范围。\nRust的生命周期规则：\n每一个引用都有一个生命周期。 生命周期是引用的有效范围。 引用的生命周期不能超过它所引用的值的生命周期。 生命周期的标记是一个单引号，比如\u0026rsquo;a。 生命周期的标记可以是任意的标识符，但是通常使用\u0026rsquo;a、\u0026lsquo;b、\u0026lsquo;c等。 生命周期的标记可以在函数签名/结构体/Trait中使用，用来指示引用的有效范围。 fn longest\u0026lt;\u0026#39;a\u0026gt;(x: \u0026amp;\u0026#39;a str, y: \u0026amp;str) -\u0026gt; \u0026amp;\u0026#39;a str { x } 智能指针 - Box https://kaisery.github.io/trpl-zh-cn/ch15-01-box.html\nRust的智能指针是一种特殊的指针，它包含了指向堆内存的指针，以及一些元数据，比如长度、容量等。智能指针可以用来管理堆内存，避免内存泄漏、野指针等问题。\nRust的智能指针有很多种，比如Box、Rc、Arc、RefCell等。其中Box是最简单的一种，它只包含了一个指向堆内存的指针，没有其他元数据。\nlet b = Box::new(5); 总结 Rust语言整体学习难度比常见高级语言要高一些，但是它的语法和特性都是非常有趣的。不推荐初学者直接从Rust开始学习，但是如果你已经有一定的编程经验而且想要尝试除C++以外的底层语言，那么Rust是一个非常好的选择。\n","permalink":"https://blog.congliu.dev/zh/posts/development/embedded/esp32-2/","summary":"\u003ch2 id=\"又学一门新语言\"\u003e又学一门新语言\u003c/h2\u003e\n\u003cp\u003e在开始单片机开发学习之前，针对esp32上较常使用的几个开发工具和语言做了一点研究。\u003c/p\u003e\n\u003cp\u003e工具主要有乐鑫官方提供的 \u003cstrong\u003eESP-IDF\u003c/strong\u003e，以及 \u003cstrong\u003eMicroPython\u003c/strong\u003e 和 \u003cstrong\u003eArduino\u003c/strong\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eESP-IDF是乐鑫官方提供的开发框架，支持C/C++，是最底层的开发方式，也是最灵活的。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMicroPython是Python的一个子集，支持Python语言，是最简单的开发方式。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eArduino是一个开源的硬件开发平台，支持C/C++，简单而成熟，是最流行的开发方式。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e考虑到生态、性能以及拓展性。决定排除MicroPython。但是我之前一直从事软件开发，基本用的都是Java/Kotlin，Python，JavaScript等不需要考虑内存释放的高级语言，对于C/C++这种底层语言，还是上大学的时候学了一点，基本都忘记了。所以这次需要从底层语言开始重新学习。\u003c/p\u003e\n\u003cp\u003e然后找到了\u003ca href=\"https://github.com/esp-rs\"\u003eesp-rs\u003c/a\u003e，发现ESP-IDF也支持Rust，而且最近Rust很火，大概看了一下语言特性，它的语法还是比较直观简洁的。无论C/C++还是Rust都要从头学，所以决定干脆学习Rust。\u003c/p\u003e\n\u003ch2 id=\"有趣的特色\"\u003e有趣的特色\u003c/h2\u003e\n\u003cp\u003e一些通用或比较简单的编程概念就不赘述了，可以通过查阅文档快速了解rust中的写法。不过Rust有一些很不同的语法和特性，这里简单列举一下。\u003c/p\u003e\n\u003ch3 id=\"强大的枚举类型---enum\"\u003e强大的枚举类型 - Enum\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://kaisery.github.io/trpl-zh-cn/ch06-01-defining-an-enum.html\"\u003ehttps://kaisery.github.io/trpl-zh-cn/ch06-01-defining-an-enum.html\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eRust的枚举类型是一种强大的数据类型，它可以包含多个不同的值，每个值可以是不同的类型。枚举类型可以用来表示一组相关的值，比如颜色、方向、状态等。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMessage\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Quit,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Move { x: \u003cspan style=\"color:#66d9ef\"\u003ei32\u003c/span\u003e, y: \u003cspan style=\"color:#66d9ef\"\u003ei32\u003c/span\u003e },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Write(String),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ChangeColor(\u003cspan style=\"color:#66d9ef\"\u003ei32\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003ei32\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003ei32\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"不一样的接口---trait\"\u003e不一样的接口 - Trait\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://kaisery.github.io/trpl-zh-cn/ch10-02-traits.html\"\u003ehttps://kaisery.github.io/trpl-zh-cn/ch10-02-traits.html\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eRust的Trait类似于其他高级语言中的接口，但是更加强大。Trait是一种抽象类型，它定义了一组方法，但是没有提供方法的具体实现。Trait可以被用来定义方法的签名，然后在具体的类型上实现这些方法。\u003c/p\u003e\n\u003cp\u003eTrait可以被用来实现多态，可以在不同的类型上实现相同的Trait，然后通过Trait对象来调用这些方法。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etrait\u003c/span\u003e Summary {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esummarize\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003eself) -\u0026gt; String;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eNewsArticle\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e headline: String,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e location: String,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e author: String,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e content: String,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eimpl\u003c/span\u003e Summary \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e NewsArticle {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esummarize\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003eself) -\u0026gt; String {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eformat!\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e, by \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e (\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#34;\u003c/span\u003e, self.headline, self.author, self.location)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"独特的内存管理---所有权\"\u003e独特的内存管理 - 所有权\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://kaisery.github.io/trpl-zh-cn/ch04-01-what-is-ownership.html\"\u003ehttps://kaisery.github.io/trpl-zh-cn/ch04-01-what-is-ownership.html\u003c/a\u003e\u003c/p\u003e","title":"RUST on Esp32 (std) - 2"},{"content":" 主要内容 在 macOS 上安装 esp32-s3 开发环境 (std版) std和no_std std 概述\n包含标准库，即乐鑫官方提供的基于C的开发框架ESP-IDF 丰富的功能: 可以访问 ESP-IDF 中存在的许多功能，包括线程、互斥锁和其他同步原语、集合、随机数生成、套接字等 可移植性 快速开发 no_std 概述\n不包含标准库，裸机开发, 但是可以使用core库中的功能 内存占用小 直接的硬件控制 实时性约束或时间关键型应用 自定义需求 S3芯片 内核：搭载低功耗 Xtensa® LX7 32 位双核处理器 主频：最高 240 MHz SRAM: 512 KB _ 片外 RAM：8 MB PSRAM 嵌入式 flash：4 MB SPI Flash 外部 flash：16 MB Flash 安装rust curl --proto \u0026#39;=https\u0026#39; --tlsv1.2 -sSf https://sh.rustup.rs | sh 安装工具链 针对 RISC-V \u0026amp; Xtensa (S3 是 Xtensa 架构) # Use `espup` to # 1. add targets for ESP32-S3 # 2. install nightly toolchain # 3. install LLVM branch for Xtensa cargo install espup # Use \u0026#34;-s\u0026#34; to skip GCC installation espup install -s std 依赖 # Install cargo-binutils brew install cmake ninja dfu-tuil # If not installed or outdated brew install python # Forward linker arguments to the actual linker executable # https://github.com/esp-rs/embuild/tree/master/ldproxy cargo install ldproxy # A library and command-line tool for flashing Espressif devices. # https://github.com/esp-rs/espflash cargo install espflash 创建项目 使用 cargo-generate 生成模版项目\ncargo install cargo-generate # Template for `std` version # https://github.com/esp-rs/esp-idf-template cargo generate esp-rs/esp-idf-template cargo 运行 # Check the serial port ls /dev/cu.usbmodem* # Check the board info espflash board-info # Flash the program cargo run 最后应该可以在终端内看到输出\n... I (401) main_task: Started on CPU0 I (411) main_task: Calling app_main() I (411) esp32_s3: Hello, world! I (411) main_task: Returned from app_main() ... 其他 对于std版本，esp-idf-sys会自动安装esp-idf，可以不需要手动安装esp-idf。 所以只需要Linux 和 macOS 平台工具链的标准设置的第一步即可。 参考资料 The Rust on ESP Book ESP-IDF 编程指南 - Linux 和 macOS 平台工具链的标准设置 ESP-IDF 编程指南 - ESP32-S3-DevKitC-1 v1.1 ","permalink":"https://blog.congliu.dev/zh/posts/development/embedded/esp32-1/","summary":"\u003cdiv class='info callout'\u003e\n  \u003cdiv class=\"callout-content\"\u003e\n    \u003cstrong\u003e主要内容\u003c/strong\u003e\n    \u003cp\u003e\n在 \u003cb\u003emacOS\u003c/b\u003e 上安装 \u003cb\u003eesp32-s3\u003c/b\u003e 开发环境 (\u003cb\u003estd\u003c/b\u003e版)\n\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\n\u003cstyle\u003e\n   \n  .callout {\n    position: relative;\n     \n    padding: 10px 0px 0px 20px;\n    margin: 20px 0;\n    border: 2px solid;\n     \n    border-radius: 8px;\n     \n    font-family: Arial, sans-serif;\n    background-color: #f9f9f9;\n    box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);\n  }\n\n  .callout-content {\n    color: black;\n  }\n\n   \n  .callout::before {\n    content: \"\\f00c\";\n     \n    font-family: \"Font Awesome 5 Free\";\n     \n    font-weight: 900;\n     \n    position: absolute;\n    left: -40px;\n     \n    top: 50%;\n    transform: translateY(-50%);\n    font-size: 24px;\n     \n    color: inherit;\n     \n  }\n\n   \n  .callout.info {\n    background-color: #e0f7fa;\n    border-color: #00acc1;\n  }\n\n  .callout.info::before {\n    content: \"\\f05a\";\n     \n  }\n\n   \n  .callout.warning {\n    background-color: #fff3e0;\n    border-color: #ff6f00;\n  }\n\n  .callout.warning::before {\n    content: \"\\f071\";\n     \n  }\n\n   \n  .callout.success {\n    background-color: #e8f5e9;\n    border-color: #43a047;\n  }\n\n  .callout.success::before {\n    content: \"\\f058\";\n     \n  }\n\n   \n  .callout.error {\n    background-color: #ffebee;\n    border-color: #e53935;\n  }\n\n  .callout.error::before {\n    content: \"\\f057\";\n     \n  }\n\u003c/style\u003e\n\u003ch2 id=\"std和no_std\"\u003e\u003ccode\u003estd\u003c/code\u003e和\u003ccode\u003eno_std\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://narukara.github.io/rust-on-esp-book-zh-cn/overview/using-the-standard-library.html\"\u003e\u003cstrong\u003estd\u003c/strong\u003e 概述\u003c/a\u003e\u003c/p\u003e","title":"RUST on Esp32 (std) - 1"},{"content":"背景 今年被几个订阅扣了不少钱，所以想找一个订阅管理软件，但是没有找到满意的，大多数订阅管理软件中每一条记录都只能有一个价格，一个连续周期。\n但是我有不少订阅的价格一直在变化（从折扣到原价，改变订阅套餐等）。我希望能够在一个订阅里管理价格的变化，并能统计相关支出和提醒。\n所以打算自己写一个。然后开始考虑是做一个APP还是小程序。相比较而言的话，小程序的开发成本更低，而且不需要用户安装，并且现在APP通知有点被滥用，可能提醒效果还不如小程序，所以决定先做一个小程序。\n开发体验 小程序从2018年开始就已经火了，现在都已经2024年了，相关文档，教程，工具都已经很成熟了。所以整体开发体验算是相当流畅了（抛开测试部份）。\n不过小程序认证以及版本审核还是有点繁琐的。如果是企业帐号应该会方便不少，但是个人的话，只能跟着相关条款修改了。\n开发工具 用的都是比较常见的技术栈了。\n前端\n微信开发者工具 后端\nApp: Nodejs + Nestjs Data: Python + FastAPI 数据库\nSqlite MongoDB 缓存\nDragonfly (Redis) 部署\nKubernetes (测试环境) Docker Compose (生产环境) 生产环境架构 部署在一台阿里云的机器上，使用Docker Compose管理容器，毕竟只有一个机器，Kubernetes有点大材小用。\n使用Traefik作为反向代理，同时也是HTTPS证书管理工具（Let\u0026rsquo;s encrypt）。\n部署了一个MongoDB Express，并没有向外暴露，方便查看和管理MongoDB。\n开发流程 毕竟是个小项目，所以开发流程尽量简单。利用Github Actions做CI/CD，每次push都会自动运行测试，然后release分支会打包Image并推送到Docker Hub。\n然后在Kubernetes（测试环境）上拉取最新的Image做测试。最后没问题再部署到生产环境。\n其他 暂时先分享这么多，贴上一个小程序的二维码，万一被有缘人看见了，欢迎体验。\n","permalink":"https://blog.congliu.dev/zh/posts/development/miniprogram/miniprogram-1/","summary":"\u003ch2 id=\"背景\"\u003e背景\u003c/h2\u003e\n\u003cp\u003e今年被几个订阅扣了不少钱，所以想找一个订阅管理软件，但是没有找到满意的，大多数订阅管理软件中每一条记录都只能有一个价格，一个连续周期。\u003c/p\u003e\n\u003cp\u003e但是我有不少订阅的价格一直在变化（从折扣到原价，改变订阅套餐等）。我希望能够在一个订阅里管理价格的变化，并能统计相关支出和提醒。\u003c/p\u003e\n\u003cp\u003e所以打算自己写一个。然后开始考虑是做一个APP还是小程序。相比较而言的话，小程序的开发成本更低，而且不需要用户安装，并且现在APP通知有点被滥用，可能提醒效果还不如小程序，所以决定先做一个小程序。\u003c/p\u003e\n\u003ch2 id=\"开发体验\"\u003e开发体验\u003c/h2\u003e\n\u003cp\u003e小程序从2018年开始就已经火了，现在都已经2024年了，相关文档，教程，工具都已经很成熟了。所以整体开发体验算是相当流畅了（抛开测试部份）。\u003c/p\u003e\n\u003cp\u003e不过小程序认证以及版本审核还是有点繁琐的。如果是企业帐号应该会方便不少，但是个人的话，只能跟着相关条款修改了。\u003c/p\u003e\n\u003ch2 id=\"开发工具\"\u003e开发工具\u003c/h2\u003e\n\u003cp\u003e用的都是比较常见的技术栈了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e前端\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e微信开发者工具\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e后端\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eApp: Nodejs + Nestjs\u003c/li\u003e\n\u003cli\u003eData: Python + FastAPI\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e数据库\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSqlite\u003c/li\u003e\n\u003cli\u003eMongoDB\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e缓存\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDragonfly (Redis)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部署\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eKubernetes (测试环境)\u003c/li\u003e\n\u003cli\u003eDocker Compose (生产环境)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"生产环境架构\"\u003e生产环境架构\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"部署架构图\" loading=\"lazy\" src=\"/images/mini-program/prod-env.png\"\u003e\u003c/p\u003e\n\u003cp\u003e部署在一台阿里云的机器上，使用Docker Compose管理容器，毕竟只有一个机器，Kubernetes有点大材小用。\u003c/p\u003e\n\u003cp\u003e使用Traefik作为反向代理，同时也是HTTPS证书管理工具（Let\u0026rsquo;s encrypt）。\u003c/p\u003e\n\u003cp\u003e部署了一个MongoDB Express，并没有向外暴露，方便查看和管理MongoDB。\u003c/p\u003e\n\u003ch2 id=\"开发流程\"\u003e开发流程\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"开发流程\" loading=\"lazy\" src=\"/images/mini-program/dev-flow.png\"\u003e\u003c/p\u003e\n\u003cp\u003e毕竟是个小项目，所以开发流程尽量简单。利用Github Actions做CI/CD，每次push都会自动运行测试，然后release分支会打包Image并推送到Docker Hub。\u003c/p\u003e\n\u003cp\u003e然后在Kubernetes（测试环境）上拉取最新的Image做测试。最后没问题再部署到生产环境。\u003c/p\u003e\n\u003ch2 id=\"其他\"\u003e其他\u003c/h2\u003e\n\u003cp\u003e暂时先分享这么多，贴上一个小程序的二维码，万一被有缘人看见了，欢迎体验。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"小程序二维码\" loading=\"lazy\" src=\"/images/mini-program/qrcode.png\"\u003e\u003c/p\u003e","title":"微信小程序开发 - 第一篇"}]