电脑技巧:分享一款免费好用的音频编辑软件——Audacity

Audacity 是一款免费、开源的音频编辑和录制软件,支持Windows、macOS、GNU/Linux等多种操作系统。这款软件由一群来自世界各地的开发者共同维护和更新,致力于为用户提供一套功能强大、易于使用的音频编辑工具。Audacity 的界面简洁直观,即使是音频编辑新手也能很快上手。

Audacity 提供了广泛的功能,涵盖了从最基本的录音到复杂的音频编辑任务,主要功能如下:

录音:可以直接从麦克风或扬声器录制声音,或者从其他音频输入设备捕捉声音。

编辑:支持剪切、复制、粘贴、删除等多种基本编辑操作,还可以撤销和重做多次修改。

多轨编辑:允许多个音频文件在同一项目中编辑,便于制作复杂的音频作品。

音频效果:内置了丰富的音频效果插件,如淡入淡出、回声、压缩、降噪等,用户可以轻松添加或移除这些效果。

频谱分析:提供频谱可视化工具,帮助用户更好地理解音频文件的组成成分。

批处理:支持通过脚本语言(如Lua)自动化处理大量音频文件。

格式转换:能够导入和导出多种音频格式,如WAV、AIFF、FLAC、MP3等。

开放源代码:Audacity 是一款开源软件,这意味着任何人都可以查看其源代码,并且开发者社区可以贡献新的功能或修复已知的问题。

跨平台兼容性:支持主流的操作系统,使得不同平台的用户都可以享受到一致的使用体验。

用户友好的界面:设计直观,即使是初学者也能快速掌握其基本操作。

广泛的文件格式支持:不仅可以处理常见的音频格式,还可以通过安装额外的插件来支持更多的文件类型。

实时预览效果:在应用任何效果之前,都可以实时预览其结果,确保编辑过程中的准确性。

定制化与扩展性:允许用户通过安装插件或编写脚本来扩展软件的功能,满足个性化需求。

双击安装程序进行安装语言选择,这里默认为简体中文。

然后进入安装向导界面

点击下一步查看软件使用说明。

接着点击下一步进入安装目录的选择

这里选择创建桌面快捷方式

然后进入软件安装准备界面。

软件安装过程如下

安装成功后界面如下:

到此软件就安装成功了。

双击桌面的软件图标,打开软件的主界面。

这里通过把一个mp3格式的音频单身道文件转换为双声道的案例给大家介绍如何使用。

首先我们选择需要转换的文件,具体如下图:

打开文件后发现只有一个

接着我们使用Ctrl+A 全选,然后Ctrl+C复制,最后使用Ctrl+V 粘贴就可以了。

接着点击导出音频

文件下拉菜单选择 导出音频

弹出窗口,这里选择导出到计算机。

接着弹出导出音频的窗口。

这里可以修改文件名、保存目录、文件保存格式、,选择后点击导出按钮。

注意:一定要选择立体声,才可以。

转换之后的效果如下:

Audacity 是一款深受音频爱好者和专业人士喜爱的音频编辑工具,无论你是需要进行简单的录音剪辑,还是复杂的音频后期制作,Audacity 都能提供必要的支持。其免费且强大的功能集合,还是非常值得推荐的。

私信回复【Audacity】获取下载地址

300元级耳夹耳机大横评:倍思、南卡和塞那,到底谁是王者?

2023年年底,华为FreeClip耳夹耳机在海外发布。尽管FreeClip不是行业内第一款耳夹形式的开放式耳机,但从行业的角度来说,FreeClip算得上是开放式耳机市场的“转折点”——和传统耳挂产品相比,FreeClip在漏音控制、轻量化等方面有着极为明显的优势。而在FreeClip的带领下,2024年的开放式耳机市场也开始朝着耳夹耳机的方向发展。

图片来源:华为

不过就像一年前耳挂耳机的情形一样,耳夹耳机作为一个全新的品类,在佩戴舒适度、用户喜欢等方面与传统TWS耳机有着明显的差异。耳夹耳机品类必须拿出足够的“诚意”降低用户的试错成本,才能吸引用户。

在2024年下半年,耳夹耳机的价格如过山车一样快速下降。在京东搜索“耳夹耳机”并以销量排序,主流产品的售价已下探至300元的价位。那么和售价是自己500%的高端产品相比,这些定位中端市场耳夹耳机,表现到底如何呢?

为了搞清楚这个问题,雷科技买来了三款300元价位的热销耳夹耳机,用横评的形式跟大家聊聊耳夹耳机如今进步到底有多大。这三款产品分别是:倍思MC1小云朵耳夹耳机(到手价249元),南卡(NANK)Clip Pro耳夹耳机(到手价289元)和塞那(SANAG)的S6S Pro耳夹耳机(279元)。

图片来源:雷科技

不同于过去带有“整活”性质的选品,小雷这次的选品要认真很多,三款耳机都是300元价位的畅销产品,且彼此之间有足够的差别。更重要的是,三款耳机都是小雷自费购买的产品,不涉及任何广告。

首先是倍思MC1小云朵耳夹耳机,到手价249元。其实在前段时间小雷已经给这款耳机做了一个单品评测。作为倍思在Eli Sport 1后的又一款明星产品,MC1小云朵为倍思在线上线下赢来了不少关注。

核心配置方面,受耳机尺寸限制,倍思无法在耳夹耳机中使用Eli Sport 1那种超大尺寸的动圈单元。但倍思依旧找到了提高耳机音质表现的方式:MC1采用的三层复合振膜拥有0.8mm的超大振幅。搭配倍思App的EQ调节,MC1的音质表现谈得上“性价比”。

图片来源:雷科技

另外,倍思MC1也提供了手机App,可以在App里对手机的EQ、低延迟模式进行调整。可能是考虑到耳夹耳机容易脱落的问题,倍思App也提供了查找耳机的选项。

第二款产品是南卡(NANK)Clip Pro耳夹耳机,到手价289元。尽管耳机看起来大,但Clip Pro的单只重量只有5.1g,戴起来毫无坠耳感。单元方面,南卡Clip Pro采用了13mm复合振膜动圈的方案,单从单元尺寸上看,Clip Pro已经来到了曾经的王者——平头塞的水准。

图片来源:雷科技

事实上,Clip Pro的设计也和平头塞非常类似——一般的耳夹耳机会用短柄连接电池和耳塞,但南卡Clip Pro的造型看起来就像一个有夹子固定的平头塞,不过像平头塞也不完全是坏事,至少耳机的音质和漏音控制更有保障。

图片来源:雷科技

我知道,第三款产品看起来很像某手机品牌那款耳夹耳机,但充电盒、耳机上的标志与其279元的到手价,证明了这款耳机并不是我们“想象中的那个它”,而是来自塞那(SANAG)的S6S Pro耳夹耳机。在京东页面上,塞那更是标注了“全球耳夹耳机销量第一”的称号。

图片来源:雷科技

在电商页面中,S6S Pro并未对其单元技术做过多介绍,只提到“超灵敏双磁振膜”技术,以及粗略的“360度ACS全景音效”“数字增强”“2倍整体音质效果提升”“58%低音品质提升”。当然了,和那个外形跟他很像,但售价是它5倍的耳机相比,塞那S6S Pro还是有些短板的,比如它不能自适应左右声道。

另外,塞那还给S6S Pro准备了一个很有意思的App——为了强调AI耳机的身份,塞那App除了支持耳机定位找回,还内置了AI翻译、AI写作大模型的功能。没错,你甚至可以在一个耳机的配套App里玩AI文生图,可以说海纳百川了。

不过既然今天是耳机横评,那三款耳机的音质表现还得是我们今天的重点。倍思这款耳机小雷之前体验过,可以说非常熟悉了。在默认EQ下,MC1的声场足够开阔,声音取向偏流行。受开放式耳机本身的限制,MC1同样存在低频衰减的情况。以《BOOM》为例,MC1的低音下沉虽然没有头戴式耳机或入耳式耳机深,但胜在低频冲击足够,鼓点干脆有节奏感。

中频部分声音有截止,主要以突出人声为目标。《Jessica》《Here》等曲目声音质感还原不错。但太强的声音风格也导致了MC1中频部分稍显薄弱和颗粒,声音细节不够丰富。当然,上述仅针对默认的倍思经典EQ,在App中大家也可以根据自己实际听感做调整。

图片来源:雷科技

刚刚说过,南卡Clip Pro类似平头塞的设计能给音质带来保障,事实上也确实如此。声音风格上,南卡Clip Pro也偏向流行风格,中频扎实、有空气感和颗粒感。不过高频方面较为单薄。以《First Love》为例,如果高频女声和复杂配乐同时出现,耳机会有解析不足的情况,声音分离度不够,毛刺也比较明显。但在清唱曲目就没有这个问题,高频截止也不那么明显。

至于塞那S6S Pro,在默认EQ下高频的毛刺感更强,高频截止也更加明显,不过中频和低频的表现能力确实不错。能在开放式耳机里做到类似半入耳耳机的低频冲击力,塞那的耳机调校确实有点东西。但从整体听感平衡来说,如果能稍微收一收低频、补足以下耳机的高频表现,整体的听感应该可以更好。

除了音质,佩戴效果也是耳夹耳机必须讨论的重点话题。这次横评里三款耳机的耳夹设计大致可以分为两类:倍思MC1和塞那S6S Pro的“C形桥”设计,和南卡Clip Pro的“”设计。

图片来源:雷科技

在讨论耳夹耳机佩戴效果时,我们需要关注的有耳机佩戴舒适度和佩戴牢固程度。为了客观中立地评价三款耳机的舒适度,小雷这次专门找了三个从未接触过这三款耳机的朋友,由他们来给三款耳机的舒适度、牢固程度排名。

图片来源:雷科技

舒适度方面,倍思MC1和南卡Clip Pro因大量运用亲肤硅胶,获得了三位用户的一致好评。其中南卡Clip Pro虽然尺寸较大,但不等长的设计让耳机背后的夹子可以夹在耳廓外侧,对耳廓背后的压力更小,佩戴同样舒适。

佩戴牢固程度方面,结构加“平头塞”设计的南卡Clip Pro是三款耳机里最不容易松动的一款。倍思MC1的钛合金丝和标志性的气垫设计可以勾住耳机,带来不错的佩戴稳定性,但塞那S6S Pro就只能靠C形桥固定了,激烈运动时可能会被甩飞。

另外,倍思MC1和塞那S6S Pro在耳朵出汗、出油后表面会变滑,松动的情况也会更明显,平时运动后最好及时清理耳机。

如果说三款耳机的音质表现只是各有千秋,那在App功能上,三款耳机可以说有着天壤之别。南卡Clip Pro不提供配套App,和以前的蓝牙耳机一样,主打“开机即用”。

倍思MC1接入倍思音频App,提供EQ调节与模式切换功能。基于手机的GPS,倍思的App也能记录耳机最后连接的地点,即使耳机丢失也有线索找回。

图片来源:雷科技

至于塞那的App,我只能用“震惊”两个字来形容。除了基础的EQ调整等设置,塞那还在App里内置了一个AI助手。就像ChatGPT等多模态AI一样,银河AI可以与用户文字、语音交流,就像AI耳机一样回答用户的语音提问,也可以进行AI翻译

图片来源:雷科技

但对塞那来说,语音问答、AI翻译这些功能显然有些大材小用了——在App里,塞那甚至提供了文生图、图生图等AIGC功能。虽然我不知道在什么情况下我们会在一个耳机App里玩体验次数有限的文生图,但从AI能力来说,塞那确实“将AI贯彻到底”。

按照惯例,我们先按照雷科技评测模板总结一下三款耳机的优缺点。

倍思MC1

优点:

1. 低延迟模式下音频时延极低;

2. 微气囊设计大幅提升佩戴舒适度。

缺点:

1. 默认EQ有明显声音取向。

南卡Clip Pro

优点:

1. 佩戴牢固且舒适

2. 充电盒小巧。

缺点:

1. 没有手机App。

塞纳S6S Pro

优点:

1. 提供大量AI功能;

2. 低音表现不错。

缺点:

1. 高频声音过于发散。

如果你想要一个价格便宜、音质不错的耳夹耳机,倍思MC1和南卡Clip Pro都是不错的选择。而如果你想要一个AI耳机,塞纳S6S Pro是你在这个价位唯一的选择。

我知道,在不少人看来,往耳机App里塞AI功能,是一种“画蛇添足”的行为,毕竟一款耳机最重要的始终还是其声音表现。但从开放式耳机的发展现况来看,塞纳这种“大杂烩”App的做法,其实也反映了这些中端价位开放式耳机面临的困局。

图片来源:雷科技

对品牌来说,中端价位意味着品牌无法在耳机里加入太多旗舰配置,比如高端耳机采用的同轴复合单元,或用来支撑开放式主动降噪的高算力AI芯片。换句话说,耳机品牌必须寻找耳机核心硬件之外的破局点。比如倍思就用“微气囊”方案打造了极佳的佩戴舒适度。塞纳也用手机App为耳机提供了附加价值。

平心而论,就AI功能的实用性来说,我并不认为塞纳App里丰富的AIGC功能能为塞纳带来多少忠实用户。但从功能方向上讲,用手机或云端的算力,为耳机提供实用的AI功能,比如语音翻译、对话百科或空间音频映射,这确实是中端开放式耳机品牌打出差异化的最佳路径。

图片来源:雷科技

就像之前说的那样,当前市面上耳夹耳机的选择还不算多。如果品牌想在价格不占明显优势的情况下,让消费者主动选择音质不如头戴式、降噪不如TWS、运动表现不如骨传导的耳夹耳机,那品牌必须围绕耳夹耳机的特性,打造更多的独家功能,比如全天可用的AI语音助手。而塞纳S6S Pro,就是“AI赋能耳机”这一产品路线的最佳样本。

从最初的骨传导耳机,到后来的耳挂式开放式耳机,再到现在小巧的耳夹耳机,开放式耳机在产品形态上已经经历了多次变革。塞纳这种看似“大杂烩”的产品策略,代表着耳机行业已经脱离音频产品概念,开始探索开放式耳机与AI融合后的耳机“新物种”。可以肯定的是,未来还将有更多的品牌加入到AI耳机这一赛道中。

更重要的是,越来越多的AI耳机,也将从产品的角度刺激AI行业,催生出更多面向耳机品类的AI功能。到那时候,耳机品牌自然不再需要在App里加入文生图功能,来给AI产品“撑场面”了。

25年1月7日,CES(国际消费电子展) 2025 即将盛大开幕,雷科技报道团已飞赴美国现场整备,届时我们将对CES展开全程专业报道,敬请关注。

Rust到底值不值得学–Rust对比、特色和理念

其实我一直弄不明白一点,那就是计算机技术的发展,是让这个世界变得简单了,还是变得更复杂了。当然这只是一个玩笑,可别把这个问题当真。

然而对于IT从业者来说,这可不是一个玩笑。几乎每一次的技术发展,都让这个生态变得更为复杂。“英年早秃”已经成为一种很普遍的现象。

Rust是近两年呼声比较高的一种新型开发语言。市场占有量并不大,但增长速度极为迅猛。有人统计过,在计算机行业,平均每33.5天就有一种所谓的新型开发语言面世,这还不包括很多企业内部、项目内部的内置简易流程工具。然而大浪淘沙,如今仍然占据着市场地位的,不过仍然是耳熟能详的有限几种。作为新来的搅局者,Rust到底值不值得学习并且在工作中应用呢?

先说结论,这里粗略的把开发者分为初学者、小有经验的常规工程师和资深开发者三类。对于初学者,Rust具有比较陡峭的学习曲线,虽然学习Rust能训练良好的编程习惯,从长远看对提高学习者的开发素养极具价值。但短期的大量付出很容易让初学者心力交瘁。并且尽管官方文档并不欠缺,但学习资料对于初学者来讲仍然是远远不够的。所以比较而言,得不偿失。因此建议初学者仍然由久经验证的语言入门加入软件开发的大家庭。比如说C/Java/Python/Js都是很好的入门选择。对于有一定经验的常规工程师,他们已经有了一段时间的开发工作实践,对于软件开发的现状、发展都已经形成了自己的世界观。如果感觉并不很喜欢这个行业,希望将来转行管理岗位或者产品岗位。那当前应当做的更多是倾向业务领域,了解业务和技术的衔接和互动,完全不需要学习Rust。而如果醉心于技术,并从中获得了自己的乐趣,希望逐步提高自己的技术水平。那么Rust会是一个很好的桥梁,哪怕仅仅学习Rust而并不将其应用于工作,也能让开发者从中获取大量的有益习惯和软件底层经验,从而形成自己良好的代码风格。对于资深工程师,即便并不从而底层系统级的开发工作,Rust也是一门很优秀的语言。它能弥补当前多种开发语言的不足,形成良好的开发哲学和思想导向,帮助开发者交付高质量的软件产品。因此,及早学习并应用Rust非常有价值。

为了说明这个结论,下面从多个角度,采用同传统语言对比的方式来说一说我对Rust的理解。

这几年有不少有影响的语言出现,但大多数都只是关键字或者小范围的语法创新,随后可能会有大量的特色库函数来丰富语言的功能。一个有经验的开发者,可能翻两天资料,就能快速的掌握。而Rust极具自身语言特点,是一种完全的创新,而不是简单的语法替换。简单的熟悉几个关键字和判断、循环等语法,远不足以掌握这门语言。为了证明这一点,下面用Rust的“所有权”(Ownership)机制和“遮蔽”(Shadowing)来举例说明。

以C++为例,请看下面这段代码:

编译执行后,程序输出:

代码再简单不过,首先声明、赋值一个字符串变量s1,然后把变量s1赋值给变量s2,最后输出两者的值。

对应的,我们看一个Rust的版本:

除了细小的语法差异,看上去跟C++的版本没有什么不同。然而在Rust中,这段代码连编译都无法通过,得益于rustc编译程序详细的输出,我们能看到很细致的错误提示:

这个编译错误是指,上面代码中,当变量s1赋值给s2之后,s1变量名所指向的内存所有权,被“转移”(move)到了s2变量名拥有之下。而从此之后,s1变量名就无效了,不再指向任何一块内存。除非重新声明并为s1赋值(Rust中称为Shadow,\”遮蔽\”原有的s1),s1不能再被使用。所有权机制可以有效的防止内存泄露所导致的程序Bug,是Rust内存管理的核心理念。上面提到的所有权“转移”是所有权管理的重要特征之一。

“遮蔽”也是一个有趣的概念,Rust的处理方式跟很多我们熟悉的语言不同。请看下面C语言代码:

这又是一段很基本的代码。首先声明、赋值一个整数变量x,接着把x的值加1,再赋值回变量x。这是各种开发语言中都常见的用法。编译执行的输出结果为x=6。来看看Rust的版本:

很不幸,这段代码同样无法编译通过,错误是:

rustc这种“图示”型的输出信息让你排查错误更加方便。错误的原因,在Rust中,默认所有变量都是只读类型的,除非在变量声明的时候就注明为可变类型\”mut\”。因此两次对于一个只读变量赋值导致编译错误。解决的办法或者注明变量为可读写,这样同C语言的版本具有完全相同的意义:

或者用我们上面提到过的“遮蔽”机制:

注意上面x=x+1,这一行的开始我们再次使用let关键字,这表示再次声明了变量x。与大多数语言不允许重复声明变量不同,这个x变量,跟第一次声明的变量x同名,并对其做出了“遮蔽”。之后除非再次遮蔽变量x,那起作用的,都将是本次新声明的x。

通过这两个例子,可以看出Rust是从理念上做出了大量创新的一种语言。如果只是像学习其它语言一样只是对比学习语法和关键字,无法真正掌握这门语言。这些融汇在语言中的理念,才是Rust最宝贵的地方。注意在这里“理念”可不是什么大而化之的套话,而是实际操作中很重要的原则。很多语言的设计初衷是“简化”,在Rust中当然也有很多简化的地方,就像直接使用“let”关键字声明一个变量,而变量的类型可以通过赋值的操作从而推导出变量的类型。比如变量超出作用域,也会被自动的回收。但Rust中也大量的存在了“复杂化”的操作,比如上面举例的所有权机制,再比如使用可读写变量需要额外标注“mut”。这些“复杂化”的部分,都基于“尽量在程序开发的早期,就将可能会出现问题的部分暴露出来,从而在设计中和编译时就解决掉。”这样一个理念。

承接自Rust的拥有权机制。引用和借用在Rust中也迥异于大量的传统语言。引用类似C语言中的指针,指向一块已经存在的数据:

上例中,y就是对变量x的引用,并且没有标注mut,所以是只读引用。写法跟C语言中获取指针的方式类似,就是一个&符号。y此时具有了变量x的一些权限,所以也称为“借用”,本例中因为只借用了读的功能,没有借用写的功能,所以称“一些”。当然也可以借用写的功能,我们后面会再举例。借用看起来跟引用是一回事,但“借用”这个词更主要对应的是上面所说的所有权“转移”的概念,转移之后,原来的变量就无效了。而借用之后,原来的变量还有效,或者部分有效,比如只被借用了写权限。

在函数参数中,使用引用的方式,从而让函数临时性的获得数据的访问权,也是典型的借用。事实上这种方式才是最常用到借用的地方:

先别管我们使用到的令人困惑的关键字和函数名,那些进入到系统学习之后都不算什么。在函数sum_vec的参数中,我们就使用了借用。顺便,我们还见识了Rust中函数的嵌套写法,当然现在新兴的语言,包括C++11之后的版本,都已经支持这种写法,这在函数式(Functional programming paradigm,注意不是函数化Functionalization)编程中是很重要的支持。

引用和借用的概念,同C/C++语言中所使用的都是很类似的,尽管名称不同。主要的区别来自于对引用的管理理念,Rust对引用的管理规则如下:

  • 对于一块内存,同时只能有一个可写引用存在
  • 对于一块内存,同时可以有多个只读引用存在
  • 对于一块内存,在有一个可写引用存在的时候,不能有其它引用存在,无论只读或者可写。
  • 引用的原始对象必须在引用存在的生命期一直有效

比如:

上面代码会产生编译错误,因为y已经是可写的引用,而同时再存在一个可写的引用z,违反了Rust对引用的管理规则。如果把z变量这一行和后面显示z的部分去掉呢?去掉之后是可以编译通过的,但仍然要注意,y此时是可写的指针,“借用”了x的写权限。所以x此时只有读的权限,不能再对x进行赋值。因为它已经被“借用走”(Borrowed)了。

这些复杂的规则,看起来就跟前面见过的所有权转移一样,似乎极大的限制了程序员的自由度。但这些都是在强迫你,让你成为一个更优秀的程序员,产生出更高质量的代码,将Bug消灭在萌芽期。

通常一个变量的生命期就是它的作用域。但在引用和借用出现后,这个问题变得复杂了。熟悉C语言的程序员都碰到过数据失效了,而指针依然存在的情况,俗称“悬挂指针”。Java为了解决这个问题干脆取消了指针,并且最终以引用计数器做为了内存管理的主要模式。

这种情况出现最多的场景,是在某个函数中使用了变量或者申请了内存,并将其引用作为返回值传递到了调用者的时候。比如这段C语言代码:

c变量位于栈上,是一个局部变量,当函数返回指针的时候,指针在这个函数的调用者中依然存在,但c变量已经被回收了。在新版本的编译器中,这种情况也会被警告,但可以编译成功。而在Rust中,这种情况是不允许编译通过的,比如下面类似代码:

编译的时候会报错“result变量没有足够长的生命期”:

如果仅仅是这样断然的禁止返回悬挂引用也就“不过如此”了。事实上更复杂的问题来自于,如果数据源来自于函数的参数,参数本身就是引用的情况。比如请看下面的Rust代码:

上面这个函数接受两个字符串的引用(实际是Slice,本文不是教学,请先忽略语法问题),比较其长度,将长的那个字符串作为结果返回调用者。顺便,这种返回值的方式一定让你印象深刻。虽然示例简单,但不可否认,这种需求是很正当的。大量的应用场景都需要函数独立于外,处理固定的内存数据,进入和返回的,都只是指向内存的指针。当然,尽管合理,上面的代码是无法编译通过的,报错是“丢失生命期指定”:

Rust引入了生命期的概念,从而保证返回值,同给定的参数,具有相同的生命期。这即保证了程序的灵活性,而又不造成内存的泄露,同时还不把维护内存安全的责任,完全推给不可靠的人为因素。

上面的代码,添加了生命期指定。在函数名之后首先声明了生命期a,语法样式跟泛型的类型说明部分实际是一样的,都放在尖括号<>之中。生命期名称之前附加一个单引号\’。随后的两个引用参数x/y以及作为返回值的字符串引用,都直接在&符号之后标注了生命期\’a。这表示,这几个引用,具有相同的生命期。当然从这里的例子,x/y是调用的参数,是外面传递进来的,所以完整的含义应当是:返回的引用值,同参数x/y一样具有相同的生命期。因此从调用者的角度来看,当x/y指向的内存,超出作用域销毁之后,所获得的函数返回值,也同时被销毁。

有一个特殊的生命期\’static,用于代表rust中的全局量或者静态量,专门表示这种引用具有贯穿于整个程序运行时的生命期长度。比如Rust中通常用字面量赋值的字符串,实际都是\’static,因为这些字面量实际在程序编译的时候就放置到了数据区并一直存在贯穿程序始终:

通过前面的几个个例子,我们对Rust的编译器rustc有了一个初步概念。丰富、详尽的编译错误输出对于排查源码中的错误帮助很大。实际上远不止于此。Rust的编译器包含着Rust语言的另外一个核心思想,那就是,尽量在编译阶段就暴露出程序的设计错误,而不让这些错误带到生产环境从而付出昂贵的代价。这也是Rust学习曲线陡峭的原因之一,很多在其它语言中可以编译通过的代码,在Rust中都无法通过编译(排除语法错误之外)。这种更严格的编译时检查很容易让初学者手足无措。带来的优点也是显而易见的,除了刚才提过的不让程序Bug带入到生产环境之外,错误能在编译阶段就消除掉,无需在运行时进行更多不必要的错误检查,这也将大大的减少程序在运行时消耗。这个消耗包括编译所生成的代码体积和运行时检查所损耗的CPU资源两个方面。

比如Rust中有多种不同功能的智能指针,以常见的Box和Rc为例,前者提供基本的指针功能,后者提供类似Java语言一样,基于引用统计的自动垃圾回收机制。(请注意我们这里并不是做语言学习,所以请关注在Rust的设计理念上,先别在意具体的关键字和语法。)

如果在程序中使用Box指针的话,当变量x被赋值给变量y,所有权同时被转移,变量x就不再可用了,这个我们在开始的所有权介绍时就见到了:

与此规则对应的所有操作,在程序的编译器就可以做出检查,从而判断是否有错误存在。但毕竟我们也有其它的需求,比如我们希望同时有多个指针指向同一块存储区域。这时候就需要使用Rc指针。

但显然,使用Rc指针的时候,我们无法在编译过程中发现可能的错误。并且,Rc指针类似Java,当对一块内存的所有引用都失效之后,系统会释放这部分内存。而这个过程,都需要在程序执行的过程中,有对应的管理代码不停的工作,以保证跟踪内存的引用和内存的释放(垃圾回收)。这就产生了运行时开销。

为了对运行时开销能够更精确的掌控,Rust在语言层面增加了许多选择,这些选择在其它语言中本来是不需要的。但一个经验丰富的程序员,则能充分的利用这些不同的选择写出高品质的代码。比如Rc指针并不支持多线程,因为其中的引用计数器操作不是原子级的,所以Rust还提供了Arc用于多线程环境。当然,原子级的操作在运行时需要额外的开销。

与Rust语言的编译设计相映成趣的是Go,Go语言提供非常快速的编译过程,从而提供流畅的开发体验,让Go语言易于学习和使用。但Go的编译质量早就为人所诟病。当然更极端的例子是Python、Js等脚本型的语言,脚本语言完全无需编译。虽然执行效率方面这些年来随着电脑性能的提高已经不是严重问题,但大多错误几乎都只能通过代码的执行来发现。使得脚本语言在商业软件开发中占有率一直不高,更别说操作系统这一类的底层软件了。

总结一下这一部分,Rust提供高级语言所具有的一些特征,比如自动的运行时垃圾回收机制。但同时也提供并且倾向于开发人员通过精细的设计,在开发和程序编译过程中就完成内存的设计和管理,从而及早发现错误,降低运行时开销,提高最终的代码质量。

面向对象是现代开发语言的基本能力。但Rust只提供了有限的面向对象支持。我衷心的认为这是一件好事,我一直认为现在很多的程序员,往往为了面向对象而去面向对象开发。把原本很简单的事情做的过于复杂,使得代码量和运行开销高企不下,开发效率和执行效率完全失控。Linus Torvalds曾经在那场著名的辩论中直呼C++是“糟糕程序员的垃圾语言”,有兴趣的可以FQ去看原文:Re: [RFC] Convert builin-mailinfo.c to use The Better String Library.

在Rust中没有直接提供“类”(class)的概念,希望使用“对象”的程序员,可以直接在结构(struct)和枚举(enum)类型上附加函数方法,比如:

看上去跟Go处理对象的方法很像是吧,其实在面向对象方面Go语言的理念也是高举了“简化”的大旗。Rust也没有我们习惯了的构造函数和析构函数。上面代码中对Circle对象的初始化语句:

就是直接对成员变量的赋值。这是因为Rust推崇“明确化”(being explicit)的代码方式,也就是所有要执行的代码,应当清晰的在代码中体现出来。而不是隐藏在一些容易忘记、容易出错的构造函数之后。

与“简化对象”相反的,Rust对面向对象中“接口”(Java中的interface,或者C++中的多重继承)的概念做了发扬,贯穿在了Rust类型管理的方方面面。当然我这样说有点不算贴切,其实应当先忘记“接口”的概念,从头理解Rust中的“特质”(trait),因为特质和接口,只是在技术实现上有些类似,但在应用理念上还是很有区别的。本质上说,“特质”也是实现多个对象中,共性的方法,比如:

随后多个对象,都可以实现这个特质,从而都具有这个方法:

在Rust中,通过泛型的帮助,根据数据类型实现的不同特质,把类型分为不同的功能和用途。比如具有“Send”特质的类型,才可以安全的在多个线程间传递从而共享数据。比如具有“Copy”特质的类型,说明数据保存在栈(Stack)上,数据的复制(赋值给其它变量),不会产生所有权的转移(参考前面所有权的例子)。还有比如,刚才说过了Rust中没有析构函数,但如果有一些数据并没有被Rust所管理,需要自己去释放,则可以为自己定义的对象实现一个Drop特质,在其中的drop方法中释放自己申请的内存:

其它面向对象的编程特征,比如“泛型”,比如“重载”,同其它语言并没有很大的区别,这里不再额外介绍。这些相比较其它面向对象语言而言,并不算丰富的语法工具,是保留了面向对象开发模式最精华的部分。并不会对业务的描述造成什么障碍,反而会让建模工作更为简洁、务实,尽可能不造成代码上的晦涩和运行时的低效。

早期出现的开发语言,比如C,比如Java,本身并没有附加官方的管理工具。比如包管理、测试管理、编译管理。在语言的发展过程中,因为开发工作的需求,往往会出现多个有影响的工具。在C/C++方面,常见的编译管理工具有Makefile/CMake/AutoMake等,包管理工具,往往同系统包管理工具结合在一起,常见的有APT/YUM/Aptitude/Dnf/HomeBrew。Java的情况也很类似。新近风靡的语言,比如Python,Pip工具占了大部分市场。Nodejs则是NPM用户最多。Go语言的同名管理工具就更不用说了。这些现象,跟语言本身的官方支持密不可分。Rust也由官方直接发布Cargo工具,功能涵盖版本升级、项目管理、包管理、测试管理、编译管理等多方面。大多数初学者的Rust之旅,就是由执行cargo new helloworld开始的。开发语言的综合管理工具,对于构建大型的软件项目必不可少。相信在cargo的帮助下,让学习者快速的学以致用,把一些项目迁移至Rust能轻松不少。

一门语言能否被大量用户支持,与语言所提供的扩展库功能密不可分。我就见到不少程序员学习Python的原因,就是因为Python能够更好的支持PyTorch / TensorFlow等机器学习工具包。Rust通过Crate(可以翻译为扩展箱)机制支持自己的扩展包。而且通过内置的Cargo工具可以直接使用大量的官方预置扩展包和社区共享的扩展包。此外Rust还可以通过FFI接口(Foreign Function Interface)直接调用其它语言编写的函数库或者共享Rust函数给其它语言调用。比如我们在Rust中调用c++写的snappy压缩、解压功能包。Snappy官方网站为:https://google.github.io/snappy/,在macOS下安装Snappy包可以使用命令:brew install snappy。

因为使用了libc扩展库,需要在Cargo.toml中设置库依赖:

编译的时候,rustc会自动链接libc库和宏定义指明的snappy压缩解压库。

把Rust中定义的函数,共享给c语言调用也很类似,请看Rust代码:

上面的代码,需要设置Cargo.toml文件的lib参数:

从而让rustc将项目编译为.dylib动态链接库文件(macOS)或者.so动态链接库文件(Linux)。对应的C语言代码:

C代码编译的时候,记着使用-l参数链接rust生成的动态链接库。综上,迁移至Rust完全不用担心扩展库的限制,也完全不用担心同现有软件资源之间的互动、共享。可以从一个小的项目作为切入点,边学边用,在享受Rust安全可靠的同时,逐渐达成软件架构的迁移。

现在流行的开发语言很多,但能够进行操作系统底层开发的选择项并没有几个。除了传统的C、新近的Go,Rust是另一个不错的选择。做到这一点,除了Rust是真正的二进制编译之外,Rust还具有非常小并且可控的“脚印”(footprint)。这代表Rust可以做到完全没有自己的运行时库支持下运行。比如官方文档中提供的一个例子:

其中#![no_std]宏代码就表示本代码编译时不使用rust标准库。想要真正从头编写一个操作系统,这个话题还是比较大,有兴趣的可以参考一下这个博客:https://os.phil-opp.com/作者Philipp Oppermann循序渐进的演示用Rust在没有标准库甚至没有libc库的支持下从头开始编写一个操作系统,该博客提供了一个学习性的实现。

作为新兴的开发语言,Rust在函数式编程、网络编程、多线程、消息同步、锁、测试代码、异常处理等方面都有不俗表现。但本文不是Rust教学,所以这里不再介绍。建议在学习Rust的过程中,根据所选教程的组织结构来逐步了解。

企业应用中,Web框架和ORM是最常用到的组件,但这应当说是Rust当前的一个短板。因为毕竟Rust是一个新兴的生态系统,尽管选择很多,但尚没有重量级的选手出现。在性能和规模化的应用方面还有待市场验证。但Rust本身对内存、性能的精细管理,让我们可以对项目的总体性能保持信心。Actix-web、hyper的web框架,以及Diesel作为ORM是比较常见的组合。

Rust首先包含了长期软件工程中对于高频Bug的经验总结,从而开创性的提出了大量的全新编程理念。不同于很多新式语言给予开发者更多的便利和自由,Rust更苛刻的对待程序员的开发工作……尽管在易用方面Rust也下了不少的功夫,但相对于繁复的规则,这些努力很容易被忽视。而这些“成长的代价”保证了更高品质的开发输出。

比如自2004年以来,微软安全响应中心(MSRC)已对所有报告过的微软安全漏洞进行了分类。根据他们提供的数据,所有微软年度补丁中约有 70%是针对内存安全漏洞的修复程序。恐怕没有人再继续做延伸统计,比如这些安全漏洞造成了多少的经济损失。所以甚至已有传闻微软正在探索使用Rust编程语言作为 C、C++和其他语言的替代方案,以此来改善应用程序的安全状况。

Rust并不适合初学者,只有经历过大量实践磨炼,甚至被安全漏洞痛苦折磨的资深开发者,才能更理解Rust的价值。

自由还是安全,终要有所取舍。

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。