Brew 使用指南

Brew 使用指南 一、什么是 brew? 全程:Homebrew macOS(或 Linux)软件包管理器。它可以让你轻松地安装、更新、卸载软件,解决软件依赖关系,你不再需要手动下载、拖拽安装或处理复杂的编译选项。 Homebrew 会将软件包安装到独立目录,并将其文件软链接至 /opt/homebrew 。 brew官网 二、安装 Homebrew 在终端(Terminal)中执行以下命令: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 安装完成后,运行以下命令确保 Brew 工作正常: brew doctor 三、基础使用命令 1. 安装软件 安装命令行工具(Formula): brew install <formula_name> # 示例:安装 wget, tree, node brew install wget tree node 安装图形界面应用(Cask) brew install --cask <cask_name> # 示例:安装 Chrome, VS Code, Spotify brew install --cask google-chrome visual-studio-code spotify 2. 查询软件 搜索软件(不确定完整包名时非常有用): brew search <keyword> # 示例:搜索所有与 python 相关的包 brew search python 查看已安装的软件列表: brew list # 列出所有通过 Formula 安装的命令行工具 brew list --cask # 列出所有通过 Cask 安装的应用程序 查看某个软件的信息: brew info <formula_name> brew info --cask <cask_name> 3....

2023年05月11日 · 3 min · Leanku

PHP 8 新特性

PHP 8 新特性 命名参数(8.0) 新增命名参数的功能: 在函数或方法调用时,可通过参数名来指定参数的值,而不仅仅依赖参数的位置 从 PHP 8.0.0 开始,函数参数列表可以包含一个尾部的逗号,这个逗号将被忽略。这在参数列表较长或包含较长的变量名的情况下特别有用,这样可以方便地垂直列出参数。 <?php function takes_many_args( $first_arg, $second_arg, $again = 'a default string', // 在 8.0.0 之前,这个尾部的逗号是不允许的。 ){ // ... } z takes_many_args(1, 2); //按照参数顺序传参 takes_many_args(first_arg:1, second_arg:2); //指定参数,不分顺序 // 类也可以使用命名参数,假设Demo类构造函数有$first_arg,$second_arg,两个参数,有takes_many_args方法 $demo = new Demo(first_arg:1, second_arg:2); $demo->takes_many_args(first_arg:1, second_arg:2); // 不能用位置的参数和命名的参数一起 // 可选参数必须在必选参数后面 例如上面的$again ?> 注解(Attributes)(8.0) 新增注解的功能。 此篇单独介绍 构造器属性提升(Constructor Property Promotion)(8.0) 新增构造器属性提升功能 在构造函数中声明类的属性)。 构造器的参数也可以相应提升为类的属性。 构造器的参数赋值给类属性的行为很普遍,否则无法操作。 而构造器提升的功能则为这种场景提供了便利。 <?php class Point { protected int $x; protected int $y; public function __construct(int $x, int $y = 0) { $this->x = $x; $this->y = $y; } } // 两个参数都传入 $p1 = new Point(4, 5); // 仅传入必填的参数。 $y 会默认取值 0。 $p2 = new Point(4); // 使用命名参数(PHP 8....

2023年05月11日 · 4 min · Leanku

Git提交日志规范指南

在软件开发流程中,Git已经成为版本控制的事实标准。每次提交代码都需要填写commit message,否则不允许提交。然而,在日常开发中,我们经常会看到各种各样模糊不清的提交信息,如“fix bug”、“更新代码”、“修改问题”等。这些不规范的commit message充斥在git history中,导致后续维护人员无法快速定位问题,有时甚至连提交者自己都不记得某次提交的目的。因此,我们需要一套统一的规范来管理和约束commit message。 规范概述 目前业界最知名的规范是Angular团队的commit message规范,它结构清晰、易于实施,已被广泛应用于开源项目和商业项目中。同时,许多IDE(如IntelliJ IDEA)也提供了相应的插件(如Git Commit Template)来辅助开发者遵循这一规范。 本文将以Angular规范为基础,详细介绍一套通用的Git commit message规范,并提供具体的操作示例。 Commit Message整体结构 规范的commit message包含三个部分:Header、Body和Footer。其格式如下: <header> <BLANK LINE> <body> <BLANK LINE> <footer> 重要说明: Header是必需的,包含type、scope和summary三个子元素 Body是必需的,用于详细描述提交内容 Footer是可选的,用于记录不兼容变更或关闭issue 关键规则:Header和Body之间必须有一个空行分隔,这是许多Git工具正确解析提交信息的前提。 整体结构示例 feat(用户认证): 增加短信验证码登录功能 为了提升用户登录体验,增加了通过手机号接收验证码进行登录的方式。 - 集成阿里云短信服务 - 新增验证码生成与校验逻辑 - 更新登录页面UI Closes #245 Header详解 Header是commit message的“标题”,格式为: <type>(<scope>): <summary> 其中,type和summary为必填项,scope为可选项。 Type:提交类别 Type用于说明本次提交的类别,必须使用以下标准化标识之一: Type 说明 使用场景 feat 新功能 新增用户可见的功能特性 fix 修复bug 修复线上或测试环境发现的缺陷 docs 文档更新 仅修改文档,不涉及代码变更 style 代码格式 不影响代码运行的格式调整(空格、缩进、分号等) refactor 代码重构 既不是新增功能,也不是修复bug的代码结构调整 perf 性能优化 提升系统性能或用户体验的代码变更 test 测试相关 新增或修改测试用例 chore 构建/工具变动 构建流程、依赖管理、辅助工具等变更 revert 回滚提交 撤销之前的某次提交 Type使用示例:...

2023年04月02日 · 3 min · Leanku

项目规范指南

项目规范指南 本规范适用于团队/开源项目的版本管理,目标是做到:规范化、可追踪、可溯源。 1. 版本管理 (Versioning) 遵循 语义化版本规范 (Semantic Versioning, SemVer 2.0.0) MAJOR.MINOR.PATCH MAJOR:主版本号,不兼容的 API 改动 MINOR:次版本号,新增功能(向下兼容) PATCH:修订号,修复 bug(向下兼容) 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。 预发布版本:1.0.0-alpha.1、2.0.0-rc.1 参考语义化版本规范:https://semver.org/lang/zh-CN/ 2. LICENSE (MIT) 作用:MIT,明确版权 规范 项目必须包含 LICENSE 文件,放置于项目根目录。 推荐使用 MIT License(宽松、常用,几乎所有开源项目可接受)。 文件名统一:LICENSE(不要写成 LICENSE.txt 或 license.md)。 在 README.md 中需明确说明 License 类型。 示例 LICENSE 文件(MIT): MIT License Copyright (c) 2025 Your Name Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal ....

2023年04月01日 · 2 min · Leanku

PHP8新特性之match表达式

PHP8 alpha2发布了,最近引入了一个新的关键字:match, 这个关键字的作用跟switch有点类似。 虽然我一般对语法糖无感,但这个我觉得还是有点意思,match这个词也挺好看,那么它是干啥的呢? 在以前我们可能会经常使用switch做值转换类的工作,类似: switch ($input) { case "true": $result = 1; break; case "false": $result = 0; break; case "null": $result = NULL; break; } (当然,有的同学会说,谁会这么写,用个数组转换不行么? 拜托,这是举例啊,数组也只能数字键和整数啊,万一key是需要其他表达式呢,万一你要多个key对应一个值呢,对吧?) 那么如果使用match关键字呢,可以变成类似: $result = match($input) { "true" => 1, "false" => 0, "null" => NULL, }; 相比switch, match会直接返回值,可以直接赋值给$result了。 并且,类似switch的多个case一个block一样,match的多个条件也可以写在一起,比如: $result = match($input) { "true", "on" => 1, "false", "off" => 0, "null", "empty", "NaN" => NULL, }; 需要注意的和switch不太一样的是,以前我们用switch可能会经常遇到这种诡异的问题: $input = "2 person"; switch ($input) { case 2: echo "bad"; break; } 你会发现,bad竟然被输出了,这是因为switch使用了宽松比较(==)。match就不会有这个问题了, 它使用的是严格比较(===),就是值和类型都要完全相等。...

2023年03月14日 · 1 min · Leanku

B+Tree

B+Tree B+Tree 是一种平衡多路搜索树,广泛应用于数据库和文件系统等领域,其核心优势在于优化磁盘存储效率和查询性能. MySQL的InnoDB存储引擎使用的索引结构就是 B+树,它是B树的一个重要变种。 1. 从B树到B+树 B树:一种自平衡的、多路的搜索树。它允许每个节点有多个子节点(多于两个,所以不是二叉树)。 B+树:在B树基础上优化而来的数据结构,是现代数据库系统中事实上的标准索引结构。 MySQL的InnoDB使用的正是 B+树。 2. 为什么数据库需要B+树? 要理解B+树,必须先理解它的设计目标。数据库的数据存储在磁盘上,磁盘I/O(读写磁盘)的速度比内存访问慢几个数量级。因此,数据库索引的核心目标是:最大限度地减少磁盘I/O次数。 B+树通过以下方式完美地实现了这一目标: 矮胖:与“瘦高”的二叉树相比,B+树每个节点可以存储非常多的键,这使得树的层级非常少(通常只有3-4层),从而保证在亿万级数据量下,查找任何一条记录最多只需要3-4次磁盘I/O。 顺序访问友好:B+树非常适合磁盘的预读特性,能够高效地进行范围查询。 3. B+树的详细结构 它由两种类型的节点组成:内部节点 和 叶子节点。 内部节点(非叶子节点) 作用:仅充当导航目录。 存储内容:只存储键值(索引列的值)和指向子节点的指针。 不存储:实际行的数据。 叶子节点 作用:存储实际的数据。 存储内容: 在 主键索引(聚簇索引) 中:叶子节点存储的就是完整的行数据。 在 辅助索引(二级索引) 中:叶子节点存储的是该索引的键值和对应的主键值。 关键特性:所有叶子节点通过指针相互连接,形成了一个有序的双向链表。这是B+树与B树的一个核心区别。 4. B+树的核心特性与优势(对比B树) 特性 B树 B+树 B+树的优势 数据存储位置 内部节点和叶子节点都存储数据。 只有叶子节点存储数据,内部节点仅为索引。 更“矮胖”的树。因为内部节点不存数据,所以一个节点能容纳的键更多,扇出(子节点数)更大,树高更低,I/O次数更少。 叶子节点链接 叶子节点之间没有链接。 叶子节点通过双向链表连接。 无敌的范围查询。要查询age BETWEEN 20 AND 30的所有记录,B+树只需找到20,然后顺着链表遍历即可。B树则需要不断地在树的中上层和下层之间来回跳跃,性能极差。 扫描和全表遍历 需要对整棵树进行复杂的中序遍历。 只需遍历底层的链表即可获得所有数据,非常高效。 对数据仓库、聚合查询等场景非常友好。 查询稳定性 由于数据可能在内部节点找到,查询时间不稳定。 任何查询都必须走到叶子节点,查询时间非常稳定。 保证了可预测的性能。 5. 在MySQL中的具体体现:聚簇索引 在MySQL InnoDB中,主键索引就是一颗B+树,并且这棵B+树的叶子节点直接存储了完整的行数据。这种索引组织表的方式被称为“聚簇索引”。 表数据文件本身就是按B+树结构组织的一个索引文件。 如果你没有定义主键,InnoDB会选择一个唯一的非空索引代替,如果没有这样的索引,它会隐式地定义一个主键。 辅助索引(二级索引) 也是一颗B+树,但它的叶子节点存储的是该索引列的值和对应记录的主键值。当通过二级索引查找数据时,需要先找到主键,再回到主键索引(聚簇索引)中查找完整数据,这个过程称为“回表”。...

2023年03月12日 · 1 min · Leanku

常用算法的PHP实现

常用算法的PHP实现 1. 快速排序 (Quick Sort) <?php function quickSort($arr) { if (count($arr) <= 1) { return $arr; } $pivot = $arr[0]; $left = $right = []; for ($i = 1; $i < count($arr); $i++) { if ($arr[$i] < $pivot) { $left[] = $arr[$i]; } else { $right[] = $arr[$i]; } } return array_merge(quickSort($left), [$pivot], quickSort($right)); } // 测试 $numbers = [64, 34, 25, 12, 22, 11, 90]; echo "原始数组: " . implode(', ', $numbers) ....

2023年03月12日 · 3 min · Leanku

数据结构

数据结构 一、说明 数据结构是计算机科学中一个非常基础和核心的概念,它对于编程、算法设计和软件工程都至关重要。 简单来说,数据结构是一种在计算机中组织、管理和存储数据的方式,目的是为了实现高效地访问和修改。 可以把它想象成一个储物系统: 把一堆书随便堆在地上,这是一种“存储”,但找起来非常困难。 使用一个带标签的书架,把书分门别类地放好,找书、放书就高效得多。 这个“书架”以及“如何给书分类、摆放”的规则,就是一种“数据结构”。 为什么数据结构如此重要? 选择合适的数据结构可以极大地影响程序的性能和效率。一个精心选择的数据结构可以让操作(如搜索、插入、删除)变得非常快;而错误的选择则可能导致程序运行缓慢甚至崩溃。 二、 常见的数据结构分类和类型 数据结构主要可以分为两大类:线性结构和非线性结构。 一、 线性数据结构 元素按顺序排列,形成一条“线”。 数组:在内存中连续存储相同类型的元素。通过索引可以快速访问任意元素。 优点:随机访问速度快。 缺点:大小固定(在某些语言中),插入和删除元素效率低。 链表:由一系列节点组成,每个节点包含数据和指向下一个节点的指针。 优点:大小动态,插入和删除元素效率高。 缺点:不能随机访问,必须从头开始遍历。 栈:一种后进先出的结构,像一摞盘子。只能在顶部进行添加(压栈)和移除(弹栈)操作。 应用:函数调用栈、撤销操作、表达式求值。 队列:一种先进先出的结构,像排队一样。从队尾添加元素,从队首移除元素。 应用:任务调度、消息队列、广度优先搜索。 变种:双端队列、优先队列。 二、 非线性数据结构 元素之间不是简单的前后关系,可能存在多个连接。 树:一种分层结构,由节点和边组成。最顶端的节点叫根节点。 二叉树:每个节点最多有两个子节点。 二叉搜索树:左子树所有节点的值小于根节点,右子树所有节点的值大于根节点。这使得搜索非常高效。 应用:文件系统、数据库索引、决策树。 图:由顶点和连接顶点的边组成。可以表示任意复杂的关系网络。 应用:社交网络、地图导航、网络路由。 哈希表:通过一个哈希函数将键映射到一个位置来访问记录,以实现极快的查找速度。 优点:在平均情况下,插入、删除和查找的时间复杂度都是 O(1)。 应用:字典、集合、缓存。 三、核心操作与算法 对于每种数据结构,我们通常关心以下几个核心操作的效率: 访问 搜索 插入 删除 这些操作的效率通常用 大O表示法 来衡量,它描述了算法时间或空间复杂度随数据规模增长的趋势。 四、作用 数据结构是构建高效算法的基石。学习数据结构能帮助你: 写出更高效的代码:理解不同操作的代价。 解决复杂问题:很多复杂问题本质上就是数据组织和处理的问题。 更好地理解计算机系统:从内存管理到数据库,底层都离不开数据结构。

2023年03月12日 · 1 min · Leanku

算法

算法 算法是计算机科学的核心基础之一,简单来说它是解决特定问题的一系列清晰指令。无论是简单的计算还是复杂的人工智能任务,都离不开算法。 1. 算法是什么? 你可以把算法想象成一个菜谱: 输入:食材(数据) 处理步骤:清晰的烹饪步骤(算法逻辑) 输出:一道菜肴(结果) 它的核心目标是用最优的方式(最快、最省资源)解决问题。 2. 算法的核心特性 一个“好”的算法通常具备以下特点: 正确性:必须能正确解决问题。 高效性:执行时间和占用空间要尽可能少。 明确性:每一步都必须清晰、无歧义。 有限性:必须在有限的步骤内结束。 3. 常见的算法类别与实例 算法种类繁多,以下是一些主要类别和经典例子: 排序算法 快速排序:采用“分治”思想,选择一个基准元素,将数组分成左右两部分,效率很高。 归并排序:也是“分治”思想,先将数组不断拆分,再合并排序,稳定且高效。 冒泡排序:反复交换相邻的逆序元素,简单但效率低。 搜索算法 二分查找:在已排序的数组中,每次比较都能排除一半的数据,效率极高(O(log n))。 深度优先搜索和广度优先搜索:用于遍历或搜索树和图结构,是许多复杂算法的基础。 图算法 Dijkstra算法:用于寻找图中两点之间的最短路径。 A*搜索算法:在Dijkstra基础上加入了启发式函数,是路径规划和游戏AI的基石。 动态规划 用于解决具有重叠子问题和最优子结构的复杂问题(如斐波那契数列、背包问题),通过存储中间结果来避免重复计算。 机器学习算法(AI领域) 线性回归/逻辑回归:用于预测和分类。 决策树/随机森林:通过树形结构做决策。 支持向量机:寻找最佳分类边界。 神经网络:模仿人脑神经元,是深度学习的核心。 4. 如何衡量算法的好坏?—— “复杂度分析” 我们使用 “大O表示法” 来描述算法的效率,主要看: 时间复杂度:随着数据规模增大,算法运行时间的增长趋势。例如 O(1), O(log n), O(n), O(n²)。 空间复杂度:随着数据规模增大,算法占用内存空间的增长趋势。 5. 为什么算法如此重要? 效率:好的算法能处理海量数据,差的算法在大数据面前寸步难行。 性能:直接影响软件和应用的反应速度与用户体验。 解决问题的基础:是开发任何软件系统、进行科学计算和实现人工智能的基石。 面试核心:是国内外大型科技公司技术面试的必考内容。

2023年03月12日 · 1 min · Leanku

我步入丛林

我步入丛林,因为我希望生活的有意义,我希望活的深刻。汲取生命中所有的精华,把非生命的一切都击溃,以免让我在生命终结时,发现自己从来没有活过! I went to the woods because I wanted to live deliberately. I wanted to live deep and suck out all the marrow of life!To put to rout allthat was not life, and not, when I had come to die, discover that I had not lived. 推荐电影《死亡诗社》 原文出自 《瓦尔登湖》-亨利·戴维·梭罗

2023年03月12日 · 1 min · Leanku