2025-04-24 22:21:27
Generated By AI
类型 | Kotlin 写法 | Java 写法 | 简要说明 |
---|---|---|---|
数字 |
Int , Long , Float , Double , Short , Byte
|
int , long , float , double , short , byte
|
Kotlin 数值类型映射到相应的原生/包装类型。 |
布尔 | Boolean |
boolean |
只能取 true /false ,与数字不互通。 |
字符 | Char |
char |
单个 Unicode 字符,支持转义序列。 |
字符串 | String |
String |
不可变;支持多行文本块 """...""" 。 |
数组 |
Array<T> , IntArray 等 |
T[] |
提供原始类型专用数组如 IntArray 、ByteArray 。 |
无符号整型 |
UInt , ULong , UShort , UByte
|
无 | 编译时检查范围,运行时越界抛 IllegalArgumentException 。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
变量定义 |
int x = 10; final String name = "Tom";
|
var x = 10 val name = "Tom"
|
var 可变,val 只读;类型由编译器推断。 |
类 + 构造 | public class P { P(String n) { ... } } |
class P(val name: String) |
主构造中声明属性,自动生成字段 & 访问器。 |
数据类 | 手动写字段/构造/equals /toString
|
data class User(val id: Int, val n: String) |
data 自动生成常用方法 & 解构组件。 |
函数定义 | public int sum(int a, int b) { return a + b; } |
fun sum(a: Int, b: Int) = a + b |
表达式函数可省略大括号和 return 。 |
空安全 | if (s != null) len = s.length(); else len = 0; |
val len = s?.length ?: 0 |
String? 可空,?. 与 ?: 插入编译期空检查。 |
分支匹配 | switch(x) { case 1: ... } |
when(x) { 1 -> ...; else -> ... } |
when 是表达式,支持范围 & 任意对象比较。 |
循环 & 集合 | for(int i=0;i<10;i++)``list.stream().filter() |
for(i in 0 until 10)``list.filter{} |
0 until 生成 IntRange ;集合链式调用基于扩展函数。 |
单例 | class S { private static S i=new S(); … } |
object S { fun foo() {} } |
object 编译时生成线程安全单例,无需额外样板。 |
特性 | 示例 | 简要说明 |
---|---|---|
默认 & 命名参数 |
fun g(msg: String = "Hi", name: String = "You") g(name="Tom")
|
编译器生成默认方法,命名参数避免重载歧义。 |
扩展函数 | fun String.ex() = uppercase() |
编译后为静态方法,第一个参数是接收者,调用如成员方法。 |
解构声明 | val (x, y) = Point(1, 2) |
data class 自动生成 componentN() ,一行取多值。 |
密封类 | sealed class R; data class Ok(val d: String): R(); object Err: R() |
限定子类范围,when 可做穷尽检查。 |
内联函数 | inline fun <T> m(b: ()->T): T { … } |
在调用处展开函数体,减少高阶函数的运行时开销。 |
集合构造器 |
listOf(1, 2) , mutableListOf("A") , mapOf("a" to 1)
|
内建集合工厂函数,语法简洁;to 表示键值对。 |
数组构造器 |
arrayOf(1, 2) , intArrayOf(1, 2)
|
支持泛型与原始类型数组,避免装箱。 |
表达式返回值 |
val max = if (a > b) a else b val result = try { … } catch { … }
|
if 、when 、try 都是表达式,可直接赋值。 |
区间语法 & 步进 |
for (i in 1..5) , for (j in 1 until 5 step 2)
|
.. 表闭区间,until 表半开,step 控制步长。 |
字符串模板 |
"Hello, $name" "Length: ${s.length}"
|
$变量 可直接拼接,复杂表达式用 ${} 。 |
Lambda 尾随语法 | list.filter { it > 0 }.map { it * 2 } |
大括号可直接跟随函数调用,链式语法自然、简洁。 |
函数 | 用法示例 | 简要说明 |
---|---|---|
let |
user?.let { print(it.name) } |
非空时执行块,it 引用原对象。 |
apply |
User().apply { age = 18 } |
在对象上执行块并返回该对象,常用于初始化。 |
also |
list.also { println("init") } |
执行副作用并返回对象,常用于日志 / 调试。 |
run |
val r = run { compute(); result } |
无接收者的作用域块,返回最后一行结果。 |
with |
with(cfg) { load(); validate() } |
对象上下文块,this 指向接收者,返回结果。 |
takeIf |
str.takeIf { it.isNotBlank() } |
条件为真返回对象,否则返回 null 。 |
sequence |
sequenceOf(1,2,3).map { … } |
惰性集合处理,适合大规模数据管道。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
泛型 | List<String> |
List<String> |
支持协变 / 逆变(out / in )和 reified 泛型函数。 |
类型别名 | 无 | typealias Name = String |
简化复杂类型声明。 |
枚举类 | enum Color { RED, GREEN } |
enum class Color { RED, GREEN } |
支持在枚举中定义属性 & 方法。 |
内联类 | 无 | @JvmInline value class USD(val amount: Int) |
编译时包装或展开,零开销封装。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
类型检查 | if (obj instanceof String) |
if (obj is String) |
is 后自动智能转换,无需显式强转。 |
安全转换 | (String) obj |
obj as String / obj as? String
|
as? 安全转换失败返回 null 。 |
基本转换 | Integer.parseInt(str) |
str.toInt() , toDouble() , toLong()
|
通过扩展函数提供常见类型转换。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
条件 & 循环 |
if , switch , for , while , do-while
|
if , when , for , while , do-while
|
when 可做表达式,替代 switch 。 |
返回 & 跳转 |
return , break , continue , throw
|
同 Java | 支持在 lambda 中局部返回,如 return@label 。 |
异常处理 |
try-catch-finally , checked exception |
try-catch-finally ,无 checked exception |
Kotlin 不区分受检异常,简化错误处理。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
包声明 | package com.example; |
package com.example |
不需要分号。 |
导入 | import java.util.List; |
import java.util.List |
支持导入顶层函数和属性。 |
别名导入 | 无 | import foo.Bar as Baz |
解决命名冲突或简化引用。 |
功能 | Java 写法 | Kotlin 写法 | 简要说明 |
---|---|---|---|
接口默认实现 | default void f() {} |
接口中可直接写方法体 | 接口内方法可有实现,无需关键字。 |
抽象类 | abstract class Shape { … } |
abstract class Shape { … } |
抽象成员不需再加 abstract 前缀。 |
继承 & 覆写 | class A extends B { @Override … } |
class A : B() { override fun … } |
用 : 表示继承,override 必显式标注。 |
可见性修饰符 |
public /protected /private
|
public /protected /private /internal
|
internal 表示同模块内可见。 |
内部类 | class Outer { class Inner {} } |
class Outer { inner class Inner {} } |
默认是静态嵌套,加 inner 变为非静态内部类。 |
场景 | Java 写法(线程/异步) | Kotlin 写法(协程) | 简要说明 |
---|---|---|---|
启动任务 | new Thread(() -> work()).start(); |
GlobalScope.launch { work() } |
协程更轻量、省资源,适合大规模并发。 |
异步返回值 | Future<Integer> f = exec.submit(...); |
val result = async { compute() }.await() |
内建 async/await ,语义更清晰。 |
延迟执行 | Thread.sleep(1000) |
delay(1000) |
非阻塞挂起,不占用线程。 |
结构化并发 | 手动管理线程池和生命周期 | coroutineScope { … } |
协程作用域自动管理生命周期,避免泄漏。 |
功能 | Java 写法(Stream) | Kotlin 写法(扩展函数) | 简要说明 |
---|---|---|---|
过滤 | list.stream().filter(x -> x > 0).collect(...) |
list.filter { it > 0 } |
语法简洁,链式调用更直观。 |
映射 | list.stream().map(x -> x * 2).collect(...) |
list.map { it * 2 } |
Lambda 简洁,扩展函数无额外依赖。 |
分组 | Collectors.groupingBy(...) |
list.groupBy { it.key } |
直接返回 Map<K, List<V>> ,更易读。 |
排序 | list.sort(Comparator.comparing(...)) |
list.sortedBy { it.prop } |
函数式排序,链式可读性好。 |
聚合 |
reduce , sum , collect
|
reduce , sumOf , fold
|
内建多种聚合函数,常用时无需额外导入。 |
持续更新中…
2025-01-02 18:37:24
whisper是一个由openai开发的通用语言识别模型,我们可以使用它来为视频自动创建字幕。
为了加速,我们需要使用GPU来进行计算,因此需要安装基于CUDA的pytorch。首先我们需要安装Miniconda,这里安装的时候直接点击下一步即可。
安装完毕之后,我们需要创建一个新的环境,这里我们创建一个名为whisper
的环境:
conda create -n whisper python=3.8conda activate whisper
安装好了Miniconda之后,我们需要安装CUDA,执行nvidia-smi
$ nvidia-smiThu Jan 2 11:49:53 2025+-----------------------------------------------------------------------------------------+| NVIDIA-SMI 560.94 Driver Version: 560.94 CUDA Version: 12.6 ||-----------------------------------------+------------------------+----------------------+| GPU Name Driver-Model | Bus-Id Disp.A | Volatile Uncorr. ECC || Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. || | | MIG M. ||=========================================+========================+======================|| 0 NVIDIA GeForce GTX 1060 6GB WDDM | 00000000:01:00.0 On | N/A || 0% 39C P8 10W / 120W | 505MiB / 6144MiB | 0% Default || | | N/A |+-----------------------------------------+------------------------+----------------------+
通过这个命令可以看到Driver Version: 560.94
和CUDA Version: 12.6
,因此我们需要安装12.6版本的CUDA,更加详细的版本对照表在这里。在安装的时候可以选择自定义安装选项,一般来说只要勾选CUDA下的 Development和Runtime即可。
安装完毕之后执行命令nvcc -V
查看CUDA版本:
$ nvcc -Vnvcc: NVIDIA (R) Cuda compiler driverCopyright (c) 2005-2024 NVIDIA CorporationBuilt on Thu_Sep_12_02:55:00_Pacific_Daylight_Time_2024Cuda compilation tools, release 12.6, V12.6.77Build cuda_12.6.r12.6/compiler.34841621_0
根据自己下载的CUDA来选择对应版本的cuDNN,下载地址在这里。下载完毕之后解压到CUDA的安装目录下,一般来说是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA{版本号}
,如果有重名的文件直接替换即可。
之后进入extras\demo_suite
目录,执行如下命令:
bandwidthTest.exedeviceQuery.exe
如果出现了PASS的字样,说明安装成功。
切换到我们之前创建的whisper
环境,使用如下命令安装CUDA版本的pytorch:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
安装之后执行python命令进入python环境,执行如下代码:
1 |
import torch |
如果显示True则说明CUDA版本的pytorch安装成功。
切换到我们之前创建的whisper
环境,执行如下命令安装whisper:
pip install -U openai-whisperpip install setuptools-rust
安装完毕之后执行如下命令就可以使用whisper了:
whisper 'C:/Users/raymond/Desktop/voice.aac' --language zh --model turbo
如上命令表示对C:/Users/raymond/Desktop/voice.aac
文件进行中文语言的识别,使用turbo模型。第一次执行该命令会下载模型文件,模型文件较大,下载时请确保网络通畅。执行结果如下
[00:00.000 --> 00:03.060] 提到肉毒毒素[00:03.060 --> 00:04.540] 你会想到什么[00:04.540 --> 00:10.820] 你真的了解它吗[00:10.820 --> 00:12.540] 2017年[00:12.540 --> 00:14.180] 肉毒毒素以万能药标签[00:14.180 --> 00:15.500] 登上时代周刊方面[00:15.500 --> 00:17.280] 目前它在全球[00:17.280 --> 00:18.960] 已被应用于几十种适应症[00:18.960 --> 00:20.560] 仅在2019年[00:20.560 --> 00:23.000] 接受注射的就已超过620万例[00:23.000 --> 00:24.880] 但不要忘了[00:24.880 --> 00:26.780] 肉毒毒素更是一种神经毒素[00:26.780 --> 00:29.000] 还曾被当作生化武器使用... 省略 ...
我们可以使用ffmpeg将音频从视频中提取出来,然后使用whisper生成字幕,最后使用ffmpeg将字幕添加到视频中。
使用如下命令提取音频:
ffmpeg -i input.mp4 -vn -acodec copy output.aac
然后使用whisper生成字幕,我们先在pycharm中创建一个test-whisper
项目,并且把python解释器设置为Miniconda创建的whisper
环境。创建一个main.py
文件,写入如下代码:
1 |
import whisper |
如上代码表示使用turbo模型,识别中文,打印详细信息,并且保存字幕文件。执行完毕之后我们可以在E:/
目录下看到生成的字幕文件。
最后我们使用ffmpeg将字幕添加到视频中:
ffmpeg -i input.mp4 -i output.srt -c:s mov_text -c:v copy -c:a copy output.mp4
之后我们在播放这个视频的时候就会有字幕了。
video-subtitle-generator
基于Anaconda的pytorch-cuda
CUDA与cuDNN的安装与配置
ffmpeg视频合并、格式转换、截图
2024-06-18 18:13:25
1 |
find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > fl.txt |
1 |
// 视频使用h.264编码,声音使用aac编码 |
crf越小,视频质量越高;crf越大,视频文件越小
编码参数也可以简写,从-vcodec
和-acodec
改为-c:v
和-c:a
:
1 |
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4 |
其中AVC/H264
和HEVC/H265
都是软件编码,速度很慢。可以选择英伟达的硬件编码:hevc_nvenc与h264_nvenc,它们使用硬件加速,速度很快。
使用英伟达显卡进行编码:
1 |
ffmpeg -i video.mp4 -c:v hevc_nvenc -crf 28 output.mp4 |
将视频从H.264转码到H.265,花了55分钟,视频体积从3.8GB减小到430MB,效果立竿见影。转码命令:ffmpeg -i 1.mp4 -c:v libx265 -vtag hvc1 -c:a copy 1_hevc.mp4
在win10可以用scoop安装ffmpeg,更新Windows上面通过scoop安装的所有程序scoop list | foreach { scoop update $_.Name }
。
将视频以同样的编码,按照指定时间进行裁剪
1 |
ffmpeg -ss 00:05 -to 08:53.500 -i ./input.mp4 -c copy video.mp4 |
利用ffmpeg快速剪辑视频
1 |
ffmpeg -ss 07:18 -to 13:45 -i ./aaa.mkv -c copy bbb.mkv |
合并视频和声音,视频使用原始编码,声音改为aac编码
1 |
ffmpeg -i 1.mp4 -i 1.opus -c:v copy -c:a aac output.mp4 |
将PNG格式图片转为JPG格式图片
1 |
ffmpeg -i image.png -preset ultrafast image.jpg |
修改图片的尺寸
1 |
ffmpeg -i image.jpeg -vf scale=413:626 2寸.jpeg |
将一个音频重复10次
1 |
ffmpeg -stream_loop 10 -i input.m4a -c copy output.m4a |
2024-01-24 19:27:14
我们在日常工作中经常会使用到很多的开源项目,开源也是一个在工作和学习中都离不开的内容。一般来说,开源项目可以选择直接开源,也可以选择捐赠给某些基金会,例如Linux Foundation、CNCF和ASF等等。以ASF为例,如果一个项目想要成为顶级项目,则需要先通过孵化器孵化,孵化结束毕业才能成为顶级项目。最近我因为一些原因参与了云原生网关APISIX开源项目,这里做一下介绍。
首先我们需要下载源代码并且构建开发流程,根据官网介绍,我们把项目代码fork到自己的仓库并clone到本地,随后在本地仓库中将原始的项目设置为上游upstream
,之后新建分支进行开发即可
~ git clone [email protected]:RitterHou/apisix.git~ cd apisix~ git remote -v~ git remote add upstream https://github.com/apache/apisix.git~ git config --global user.name "derobukal"~ git config --global user.email "[email protected]"~ git fetch upstream~ git checkout master~ git rebase upstream/master~ git push origin master~ git checkout -b issue-10484~ cd ..
根据官方教程,我们还需要安装APISIX的开发环境注1
~ export https_proxy="http://192.168.65.100:7890"~ export http_proxy="http://192.168.65.100:7890"~ wget https://raw.githubusercontent.com/apache/apisix/master/utils/install-dependencies.sh~ APISIX_RUNTIME='1.1.1' bash install-dependencies.sh~ cd apisix~ make deps~ sudo mkdir /usr/local/apisix~ sudo mkdir /usr/local/apisix/logs~ sudo chown raymond:raymond /usr/local/apisix -R~ sudo make install
以及安装和启动etcd
~ ETCD_VERSION='3.4.18' wget https://github.com/etcd-io/etcd/releases/download/v${ETCD_VERSION}/etcd-v${ETCD_VERSION}-linux-amd64.tar.gz && tar -xvf etcd-v${ETCD_VERSION}-linux-amd64.tar.gz && cd etcd-v${ETCD_VERSION}-linux-amd64 && sudo cp -a etcd etcdctl /usr/bin/~ cd ..~ etcd
搭建好了环境之后,就可以修改代码并提交PR了。一般来说开源项目都会有多种类型的改动,以apisix为例,它限制了PR可以为固定的几种类型:
featfixdocsstylerefactorperftestbuildcichorerevertchange
包含了文档修改、新功能、bug修复等等,我们选择比较简单的文档修改作为第一个PR。我在使用APISIX的过程中,发现它证书相关的文档中存在一个错误
在上图中,这里的地址不应该是/hello
而应该是/get
,因此我们可以在本地仓库新建一个分支并对这个问题作出修改。修改后我们将这次改动提交(为了使提交更加的清晰和安全,建议合并commit并对commit进行签名)并push到我们自己的远程仓库,随后在GitHub上面创建一个针对原始仓库的Pull Request。一般项目在创建一个PR的时候都会有模板信息,照着模板信息进行填写即可,填写完毕就可以提交PR并等待项目的成员进行处理了
在APISIX中有着很多的ISSUE
我们可以关注这些ISSUE看有没有自己能解决的问题。一般来说,带有good first issue
标签的都是比较简单并且适合新人的,我们可以优先从这些issue中寻找自己能解决的问题
在确定了issue之后,我们可以请求管理员将这个issue分配给自己,防止别人也会去解决这个问题从而浪费时间。当然,有的时候issue即使已经被分配给别人了,但是如果他一直没有解决这个问题,我们仍然可以请求将这个issue分配给自己
对于issue-10484,因为涉及到代码更改,因此需要执行测试。APISIX使用了test-nginx框架来执行测试,官方有关于如何进行测试的介绍
我们需要安装测试框架注2
sudo cpan Test::Nginx
并下载依赖测试模块
➜ apisix git:(issue-10484) git clone https://github.com/api7/test-toolkit/ t/toolkit
修改完代码之后可以执行相关的测试
~ PATH=/usr/local/openresty/nginx/sbin:/usr/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/admin/ssl2.tt/admin/ssl2.t .. ok All tests successful.Files=1, Tests=52, 11 wallclock secs ( 0.06 usr 0.01 sys + 3.61 cusr 1.05 csys = 4.73 CPU)Result: PASS
如果测试没有问题就可以提交PR了。
apisix使用GitHub的workflow进行CI执行测试,以redhat-ci.yaml为例,它会在多个平台上执行多个文件夹内的测试。
1 |
jobs: |
如上所示,GitHub action中的matrix默认会对其下面的的多个选项进行合并,例如redhat-ci.yaml
的events_module
和test_dir
组合起来就会构成8个执行脚本
lua-resty-worker-events t/plugin/[a-k]*lua-resty-worker-events t/plugin/[l-z]*lua-resty-worker-events t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misclua-resty-worker-events t/node t/pubsub t/router t/script t/secret t/stream-node t/utils t/xds-librarylua-resty-events t/plugin/[a-k]*lua-resty-events t/plugin/[l-z]*lua-resty-events t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misclua-resty-events t/node t/pubsub t/router t/script t/secret t/stream-node t/utils t/xds-library
github的CI会对这些所有的任务执行测试。如果测试执行失败了,需要重点关注失败的日志,并在本地调试直到可以通过测试。如果遇到数据不对的问题,可以重新对数据进行初始化
apisix quit && apisix init && apisix init_etcd && apisix start
在代码提交并创建了PR之后,我们可能会收到一些反馈,这时候我们就需要针对这些反馈作出回应。以#10771为例
我在提交了代码之后,管理员认为需要将aes_encrypt_pkey
和aes_decrypt_pkey
方法中的field
字段去掉。我一开始在写代码的时候就发现这个字段去掉会导致数据加解密过程中ssl
和data
的行为不一致,可能导致错误。不过管理员让我放心删,没问题,本着信任的态度我就把参数删除掉了
但是删除掉了之后测试却怎么也跑不过,我因为非常信任社区管理员也没有怀疑是因为ssl
和data
逻辑不一致导致的,而是从其它地方入手进行排查。最终花了大量的时间经过了很多**的排查之后,发现其实就是因为ssl
和data
的行为逻辑不一致导致的。我随后询问了管理员,并且把field
参数加了回来
把field
参数加回来之后,所有的test cases就都能跑过了
所有测试用例通过,一段时间之后PR被review没有问题,就会被合并到master分支了
Revolution OS
S04E00-吴晟:开源项目进入 Apache 孵化器意味着什么
Apache 是如何运作的?
新手如何快速参与开源项目
如何从小白成长为 Apache Committer?
在执行install-dependencies.sh
脚本的时候,会下载golang的依赖,比如gRPC-Go,这里需要保证网络能够顺畅访问golang的官方仓库。
为了保证test-nginx正常安装,需要网络顺畅,能够正常访问相关资源。
2024-01-06 06:00:22
最近需要远程访问一台虚拟机内的Linux,因为虚拟机没有公网IP,因此选择使用frp转发ssh流量的方式来实现远程访问。首先访问frp的release页面并根据操作系统和CPU下载相应的版本,之后解压得到frpc
和frps
文件。
frps是服务端版本,它需要部署在一台拥有公网IP的主机上,它的配置frps.ini
如下
[common]bind_port = 10625token = y9XBLEu2ymW1s5N3W7OuDPhUG4IohVmQ
其中bind_port代表了它所监听的端口号,而token则是客户端连接时需要用到的验证信息。
frpc是客户端版本,它的配置frpc.ini
如下
[common]server_addr = 100.26.21.285server_port = 10625authentication_method = token token = y9XBLEu2ymW1s5N3W7OuDPhUG4IohVmQ[ssh]type = tcplocal_ip = 127.0.0.1 local_port = 22remote_port = 10626
common代表通用配置,它包含了4个配置
ssh代表了进行ssh转发的设置,它的含义如下
有了如上的配置之后,我们可以在远程主机上使用该配置启动frps
./frps -c ./frps.ini
需要注意远程主机的10625和10626端口需要关闭防火墙的设置,以保证可以通过外部进行访问。之后启用本地的客户端
./frpc -c ./frpc.ini
本地机器如果没有安装ssh服务,则需要先安装ssh服务。启动了服务端和客户端之后,可以在服务端看到客户端成功连接的日志信息,之后通过
ssh [email protected] -p 10626
命令就可以成功访问虚拟机内Linux的ssh服务了,整个网络流程大致如下
2023-10-19 00:18:09
首先我们安装zsh,并切换默认的shell为zsh,之后重启进入zsh
sudo apt-get install zshchsh -s /bin/zshsudo shutdown -r now
之后我们安装oh-my-zsh,因为网络的原因所以设置了代理
wget -e https_proxy=192.168.65.100:7890 https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.shchmod +x install.sh./install.sh
然后再安装zsh命令自动补全插件zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
之后编辑~/.zshrc
文件,修改ZSH_THEME="simple"
,并且在plugins
里面添加zsh-autosuggestions
配置
ZSH_THEME="simple"plugins=(git zsh-autosuggestions)