跳转至

编程语言

Python 泛型与型变完全指南:从宠物医院看类型安全

引言:兽医科室的类型危机

假设你经营一家宠物医院。你有一个 "犬科专科住院部",只收治狗狗。某天,由于"动物住院部"床位紧张,护士打算把一只刚送来的哈士奇安排进"犬科专科住院部"——毕竟狗也是动物,对吧?

问题出现了:如果允许这样做,其他医生可能基于"这是普通动物住院部"的认知,往里面收治一只猫。结果当你去查房时,期待看到一只狗,却发现笼子里是一只猫——类型契约被破坏了

class Animal: pass
class Dog(Animal): pass  
class Cat(Animal): pass

class Ward(Generic[T]):  # 住院部
    def admit(self, patient: T) -> None: ...      # 收治(写入)
    def discharge(self) -> T: ...                 # 出院(读取)

def general_ward(ward: Ward[Animal]) -> None:
    ward.admit(Cat())  # 对于普通动物病房,收治猫很合理!

dog_ward = Ward[Dog]()  # 犬科专科
general_ward(dog_ward)  # ❌ 类型检查器阻止了这一步!
# 如果允许:下一行会在运行时出问题
dog: Dog = dog_ward.discharge()  # 期望得到狗,结果可能是猫!

这个"猫住进犬科病房"的问题,引出了泛型编程中最核心的概念:型变(Variance)

Python 上下文管理器深度解析:从资源管控到优雅编程

在 Python 编程中,资源管理是最容易引发错误的领域之一。文件未关闭、锁未释放、数据库连接泄漏——这些问题往往不会在代码运行时立即显现,而是在高并发或长时间运行的系统中突然爆发。

传统的 try-finally 模式虽然能保证资源释放,但会带来代码臃肿和逻辑分散的问题:

# 传统方式:繁琐且容易出错
f = open('data.txt', 'r')
try:
    data = f.read()
    process(data)
finally:
    f.close()  # 忘记写这一行,文件句柄就泄漏了

Python 的 Context Manager(上下文管理器) 正是为了解决这一痛点而生。通过 with 语句,它将资源获取与释放绑定在一起,实现了确定性清理(Deterministic Cleanup)

Python 包与模块机制深度解析:从 import 到底层命名空间

在 Python 工程中,我们每天都在写 import xxx,但很少停下来思考:当解释器执行这行代码时,内存中到底发生了什么?为什么有时候 import 一个文件夹就能使用其中的功能,有时候却不行?__init__.py 到底扮演着什么角色?

本文将从模块即对象的本质出发,深入解析 Python 的包管理机制,帮你建立对 import 系统的完整认知。

Package 与 Module:容器与内容的关系

首先明确一个常被混淆的概念:Package 本质是包含 Python 文件的文件夹,而 Module 是具体的 Python 文件

mymath/                 ← 这是一个 Package
    __init__.py
    calculator.py       ← 这是一个 Module
    geometry.py         ← 这是另一个 Module

关键区别在于:Package 是一个命名空间容器,Module 是实际执行代码的单元。当你执行 import mymath 时,Python 并不是递归执行包内所有 .py 文件,而是精确地执行 mymath/__init__.py,并将这个包目录封装成一个 module 对象。

这种设计体现了 Python 的显式优于隐式哲学——你需要在 __init__.py 中明确声明"这个包对外暴露什么",而不是自动暴露所有子模块。

ConnectRPC:下一代 Protobuf RPC 框架——当 gRPC 遇见现代 Web 开发

为什么我们需要"更好的 gRPC"?

自 2016 年 Google 开源 gRPC 以来,它凭借 Protocol Buffers 的高效序列化和 HTTP/2 的多路复用,迅速成为微服务间通信的事实标准。然而,随着云原生架构的演进和前后端分离开发的普及,gRPC 的一些设计局限日益凸显:

  • 浏览器兼容性:gRPC 依赖 HTTP/2 的底层特性,浏览器无法直接调用,必须借助 grpc-web + Envoy 代理
  • 调试困难:二进制协议让 curl 和浏览器开发者工具束手无策
  • 部署复杂:需要特殊的负载均衡器支持 HTTP/2 trailers
  • 代码冗长:生成的客户端代码模板化严重,与现代开发体验脱节

ConnectRPC(简称 Connect)正是 Buf 团队为解决这些痛点而打造的现代化 RPC 框架。它不仅完全兼容 gRPC 生态,更带来了浏览器原生支持、HTTP/1.1 回退、以及 REST 般的调试体验。

Python 类型注解完全指南

为什么要用类型注解?

Python 是一门动态类型语言,变量类型在运行时才确定。这种灵活性带来了快速开发的优势,但也埋下了隐患:

# 没有类型注解时,这个 bug 可能在生产环境才暴露
def calculate_total(price, quantity):
    return price * quantity

# 调用者可能传入错误类型,而 Python 不会提前报错
result = calculate_total("100", "5")  # 结果是 "100100100100100",而非 500

类型注解(Type Hints)PEP 484(Python 3.5)中引入,它解决了以下核心痛点:

痛点 解决方案
IDE 智能提示弱 PyCharm/VSCode 能基于类型提供精准的自动补全和跳转
代码可读性差 函数签名即文档,无需阅读实现即可了解接口
重构风险高 修改函数参数时,类型检查器能发现所有调用点
团队协作难 接口契约显性化,减少沟通成本
文档不同步 类型注解即实时文档,不会过时

一文带你理解Dart空安全

原文:Understanding null safety

作者: 鲍勃·尼斯特罗姆,写于 2020年7月

自 Dart 2.0 中用可靠的静态类型系统替换了原有的不完善的可选类型系统以来,空安全是我们对 Dart 做出的最大改动。Dart 最初发布时,编译时空安全还是一项罕见的特性,需要详细讲解。如今,Kotlin、Swift、Rust 和其他语言都针对这个已经非常普遍的问题提供了各自的解决方案。以下是一个示例:

// 无空安全:
bool isEmpty(String string) => string.length == 0;

void main() {
  isEmpty(null);
}

如果运行这段 Dart 程序时没有启用空安全机制,它会在调用 .length 方法时抛出 NoSuchMethodError 异常。因为空值是 Null 类的一个实例,而 Null 类没有 length 方法。运行时错误非常糟糕。对于像 Dart 这样旨在运行在终端用户设备上的语言来说,这一点尤为重要。如果服务器应用程序崩溃,通常可以在用户注意到之前重启它。但是,当 Flutter 应用在​​用户的手机上崩溃时,用户会非常不满意。用户不满意,开发者自然也不会满意。

开发者喜欢像 Dart 这样的静态类型语言,因为它们允许类型检查器在编译时(通常直接在 IDE 中)查找代码中的错误。越早发现 bug,就能越早修复它。当语言设计者谈到“修复空引用错误”时,他们指的是增强静态类型检查器的功能,使语言能够检测到类似上述尝试对可能为空的值调用 .length 的错误。

Flutter布局终极指南:轻松布局 Flutter 组件的唯一指南

原文:The Ultimate Flutter Layout Guide:The only guide you need to layout your Flutter widgets hassle-free

引言

你在构建 Flutter 应用时是否曾被以下错误困扰过?

  • A RenderFlex overflowed…(RenderFlex 溢出…)
  • RenderBox was not laid out(RenderBox 未布局)
  • Viewport was given unbounded height(Viewport 被赋予了无限高度)
  • An InputDecorator …cannot have an unbounded width(InputDecorator 不能拥有无限宽度)
  • Incorrect use of ParentData widget(ParentData 组件使用不正确)

如果答案是肯定的,那么这篇博客文章就是为你准备的!

在这篇博客文章中,我将讨论并分享一些常见的 Flutter 布局场景和最佳实践。我会更多地关注代码片段,而不是组件细节。对于组件详情,我会分享相关链接。

单个子元素布局组件

Align(对齐)

一个将其子组件在其内部对齐的组件,并可选择根据子组件的大小调整自身大小。

Center(
  child: Container(
    height: 120.0,
    width: 120.0,
    color: Colors.blue[50],
    child: const Align(
      alignment: Alignment.topRight,
      child: FlutterLogo(
        size: 60,
      ),
    ),
  ),
)

Python 项目结构与打包完全指南:从入门到实践

当你完成一个 Python 项目,想要发布到 PyPI 供全球开发者下载时,你是否遇到过这些困惑:

  • pip install 背后到底发生了什么?
  • 为什么安装 beautifulsoup4 却要 import bs4
  • 项目代码应该放在根目录还是 src 目录?
  • python -m builduv build 有什么区别?

本文将从依赖安装的底层机制出发,逐步深入到 WHL 文件构建流程,最后探讨现代化项目结构的最佳实践。无论你是刚接触 Python 打包的新手,还是希望迁移到现代工具链的开发者,这篇文章都能给你清晰的指引。

依赖安装机制:当你执行 pip install 时发生了什么?

软件包从哪来?——PyPI 与 WHL 文件

当你执行 pip install flask 时,工具背后做了三件核心的事:

  1. 查询元数据:向 PyPI(Python Package Index,Python 官方的软件包仓库)请求 flask 的包信息
  2. 下载 WHL 文件:根据你的 Python 版本和操作系统,选择最合适的 .whl 文件下载
  3. 解压安装:将 WHL 文件解压到当前 Python 环境的 site-packages 目录

WHL(Wheel) 是 Python 的二进制分发格式标准(由 PEP 427 定义)。它本质上就是一个 ZIP 压缩包,里面包含了:

  • 预编译的代码(或纯 Python 源代码)
  • 包的元数据(依赖关系、版本信息等)

让我们以 Flask 3.1.1 为例,看看 WHL 文件的真面目:

# 下载 Flask 的 WHL 文件(不安装)
pip download flask==3.1.1 -d ./downloads

# 查看 WHL 内容(WHL 就是 ZIP)
unzip -l ./downloads/flask-3.1.1-py3-none-any.whl

Go语言常见使用错误总结

在学习和使用 Go 语言的过程中,我们不可避免地会遇到一些陷阱和常见的使用错误。这些建议性错误或潜在的问题,有时可能会在代码中悄悄滋生,直到某一天给你带来难以察觉的 bug。为了帮助大家更好地理解和规避这些陷阱,我整理了一些 Go 语言中常见的使用错误,这些建议或许能成为你编写更健壮、可维护代码的助力。

本篇博客旨在提醒读者注意一些在 Go 语言中易犯的错误,不仅包括语法和语义级别的问题,还包括一些最佳实践和规范。通过深入理解这些错误,我们可以更好地规避潜在的风险,写出更高效、更稳定的 Go 代码。

在我们开始探索这些错误之前,让我们一同回顾一下“在错误中学习,不断成长”的理念。编程世界中,错误不是失败的代名词,而是成长的机会。当我们深入了解常见错误时,我们更能够逐步提升自己的编程技能,写出更加健壮的代码。

愿这篇博客能够帮助你更好地使用 Go 语言,避免一些不必要的困扰。让我们开始我们的探索之旅,一同领略 Go 语言的优雅之美,并在编程的路上越走越远。

Happy coding! 🚀

切片相关

对切片并发地进行append操作

append操作是并发不安全的,在使用过程中,需要特别注意。下面代码中是有问题的:

func append_to_slice(s []int, i int) {
    append(s, i)
}

var slices = []int{1,2, 3}
go append_to_slice(slices, 4)
go append_to_slice(slices, 5)

解决办法之一是我们可以使用sync.Mutex进行加锁处理。

如何在微控制器中运行Rust?

原文:Running Rust on Microcontrollers

概览

Rust 是一个相当新的编程语言(它诞生于20101年),但在开发嵌入式固件方面显示出巨大的潜力。它首先被设计为一种系统编程语言,这使得它特别适合用于微控制器。它试图通过实现一个强大的所有权模型(可以消除整个错误类的发生)来改进 C/C++ 的一些最大缺点,这对固件也非常适用。

截至2022年,CC++ 编程语言仍然是嵌入式固件的事实标准。然而 Rust 在固件中的角色看起来很光明。Rust 对固件的支持并不是后面才考虑到,而是一开始就考虑支持。 为此,Rust 专门有官方的 嵌入式设备工作组 和 介绍如何使用 Rust 进行嵌入式开发的 嵌入式Rust之书。下图就是Rust嵌入式设备工作组logo2

Rust嵌入式设备工作组logo

本篇文章旨在探索在微控制器(这里指的是低级嵌入式固件,而不是在 Linux 等主机环境上运行)上运行 Rust,涵盖以下内容:

  • 语言特性
  • 架构支持
  • MCU家族支持
  • IDE, 编码 和 编码体验
  • 实时操作系统
  • Rust缺点