这样设置 VS Code,超级提升你的工作效率!
VS Code是一个开源的跨平台开发工具,是我目前用的最顺手的编辑器。本文介绍了一些常用的插件和快捷键,帮你大大提高软件开发的效率,让你有更多的时间去撸铁和泡妹子。
初识VS Code
先放上它的官网:
https://code.visualstudio.com/
VSCode全称是Visual Studio Code,光从名字上来看,一开始可能有人会把VSCode和Visual Studio搞混,他俩都属于微软爸爸公司旗下的产品,而后者早已名声在外,长期占据程序员最喜爱编辑器榜首,为了让新儿子VSCode蹭蹭热度,所以起一个差不多的名字,就像Javascript之于Java。
说VSCode是个新生儿,一点都不为过,从它诞生到现在也只是过了4年时间,跟历史悠久的各大编辑器相比它只是个弟弟。但是就在最近的一到两年,它高速成长,市场占有率开始飙升,远远领先于其他的编辑器,Sublime Text迅速下降,Atom不温不火,WebStorm由于收费问题一直在国内的使用率不高,Vim由于学习成本太高也渐渐退出历史舞台。如果你正好从别的编辑器转到VS Code也完全不用担心,它提供了对应的Keymap插件,可以将你的键盘设置迁移过来,帮你快速上手操作,而不用再重新花时间去适应快捷键。
而且它为每一种语言都提供了很好的支持,将开发中需要用到的Extension打包成一个合集,基本上开发的时候下载对应的Extension Package就可以获得很好的支持。
微软给VSCode的定义就是:免费、开源、跨平台。重新定义代码编辑器。再加上去年微软收购Github的举动,这些都说明微软在开源方面有了越来越多的尝试。
开源对于一个产品的长期发展极为重要。在四款编辑器中,Sublime 是闭源的,VS Code、Vim 和 Atom 都是开源的,而 VS Code 可以说是开源做的最好的。
VS Code 不仅仅是把代码开源出来。而是把整个产品的开发过程建立于开源之上,与整个社区深入合作,倾听用户在 GitHub 上的反馈,使 VS Code 越做越好:
每一年,VS Code 团队都会在 GitHub Wiki 发布 Roadmap ,列出一整年的规划图。
每个月初,在产品设计阶段,VS Code 团队会在 GitHub Issue 上会发布 Iteration Plan ,列出这个月会做的每一个功能,每一个功能基本会对应一个 GitHub Issue,你可以看到详细的设计以及 mockup,并且可以提出你自己的见解。
每个月末,临近产品发布,你可以在 GitHub 看到 Endgame 了解到 VS Code 是如何进行产品测试与发布的。
不仅代码开源,VS Code 整个产品的计划,设计以及发布管理都是“开源”的:每一个阶段对每一个用户是公开透明的,你不仅可以开 Issue,发PR,你甚至也可以参与到每个功能的设计与讨论中去!
关于VSCode业界一直有一个争议——它到底是不是一个IDE?对于Visual Studio,微软直接就把它定义为同类中最好用的IDE,而对于VSCode,微软目前还只是把它定义为一个Code Editor。
Visual Studio Code is a lightweight but powerful source code editor
为了解决这个问题,我们首先要搞清楚一个概念,什么是IDE?它的全称是Integrated development environment,字面意思是集成开发环境,也就是说把开发过程中的一些主要活动和使用到的工具都集成在一个开发环境中,这样我们就可以在一个程序里进行编写代码、调试代码、运行命令行、版本控制等开发过程。
目前VSCode拥有强大的API支持,已经基本可以实现IDE。我们用它编写代码,运用内置的Terminal终端快速的运行命令行,下载Debug插件,设置断点,轻松调试代码。使用内置的Git进行版本控制,轻松管理源代码。不论哪种语言都可以下载到相应的插件合集,一次性打包安装,整个开发过程都可以在这个一个工具中完成,它真正做到了重新定义代码编辑器,在Stack Overflow的2018年开发者调查中,VS Code成为了最受欢迎的开发工具。
基本插件
这个部分介绍一些必装的开发插件,帮你大大提升代码编辑效率。
VS Code 有着丰富且快速增长的插件生态,如今,已经有超过一万个插件。不仅有中心化的插件市场,而且在 VS Code 编辑器里也可以轻松搜索插件,直接进行安装与管理。相比之下,Sublime 只有 5000 不到的插件,而且在编辑器里不能很方便地搜索管理插件;Vim 插件虽多,但因为没有一个中心化的插件市场,查找插件很麻烦;Atom 有 8000 多的插件,比 VS Code 少一些,虽然在编辑器内也是可以查找插件,但 VS Code 的搜索和浏览功能做的要比 Atom 要好。
Chinese(Simplified) Language Pack for Visual Stidio Code 中文汉化包
对于一些英文不太好的小伙伴,上来第一件事肯定是要切换成中文语言环境,安装汉化包插件之后,按快捷键Ctrl+Shift+P调出命令面板,输入Configure Display Language,选择zh-ch,然后重启vs code即可。
open-in-browser 在浏览器中查看
VS Code没有提供直接在浏览器中运行程序的内置功能,所以我们需要安装此插件,在浏览器中查看我们的程序运行效果。
Live Server 实时预览
安装这个插件之后,我们在编辑器中修改代码,按Ctrl+S保存,修改效果就会实时同步,显示在浏览器中,再不用手动刷新。
[图片上传失败...(image-9b80fc-1564194236095)]
Auto Close Tag 自动闭合标签
输入标签名称的时候自动生成闭合标签,特别方便。
Auto Rename Tag 尾部闭合标签同步修改
自动检测配对标签,同步修改。
Bracket Pair Colorizer 用不同颜色高亮显示匹配的括号
对配对的括号进行着色,方便区分,未安装该插件之前括号统一都是白色的。
Highlight Matching Tag 高亮显示匹配标签
这个插件自动帮我们将选中的匹配标签高亮显示,再也不用费劲查找了。
Vscode-icons VSCode 文件图标
此插件可以帮助我们根据不同的文件类型生成对应的图标,这样我们在侧边栏查看文件列表的时候直接通过图标就可以区分文件类型。
使用mac的小伙伴可以选择下载Vscode-icons-mac,基本图标与Vscode-icons类似,就是文件夹采用的是mac风格。
TODO Highlight 高亮
如果我们在编写代码时想在某个地方做一个标记,后续再来完善或者修改里面的内容,可以利用此插件高亮显示,之后可以帮助我们快速定位到需要修改的代码行。
Code Spell Checker 单词拼写检查
我们在编写代码的时候经常会不小心拼写错误造成软件运行失败,安装这个插件后会自动帮我们识别单词拼写错误并且给出修改建议,大大帮我们减轻了排除bug的压力。
Code Runner 运行选中代码段
如果你需要学习或者接触各种各样的开发语言,那么 Code Runner 插件可以让你不用搭建各种语言的开发环境,直接通过此插件就可以直接运行对应语言的代码,非常适合学习或测试各种开发语言,使用方式直接右键选择Run Code,支持大量语言,包括Node。
Improt Cost 成本提示
这个插件可以在你导入工具包的时候提示这个包的体积,如果体积过大就需要考虑压缩包,为后期上线优化做准备。
GitLens 查看Git信息
将光标移到代码行上,即可显示当前行最近的commit信息和作者,多人开发的时候十分有用,责任到人,防止甩锅。
Bookmarks 书签
对代码进行书签标记,通过快捷键实现快速跳转到书签位置。
具体的快捷键可以在键盘快捷方式中自定义设置:
拓展插件
这部分主要介绍一些针对特定开发环境的插件
Vscode-element-helper
使用element-ui库的可以安装这个插件,编写标签时自动提示element标签名称。
Version Lens 工具包版本信息
在package.json中显示你下载安装的npm工具包的版本信息,同时会告诉你当前包的最新版本。
Vetur VUE语言包
VUE是时下最流行的js框架之一,很多公司都会选择基于VUE来构建产品,Vetur对VUE提供了很好的语言支持。
没有安装该插件之前之前编写后缀名为.vue的文件时代码是白色的
安装插件后编写vue文件输入s,按Tab键就可以自动补全模版。
WakaTime 计算代码工作量
这是一款时间记录工具,它可以帮助你在vs code中记录有效的编程的时间。
并且将数据用折线图的形式展示出来,为你呈现一周内的工作趋势,曾经编写项目的时候最多一天编程将近12个小时,你的付出和努力wakatime都知道。
同时在他的官网中,也会显示用扇形图的形式显示你编写各个语言所占用的时间比例,以及你在各个项目中所用的时间占比,是一个非常好的数据报告,项目结束的时候你可以在它的Dashboard中清晰地看出自己的时间都是如何分配的。
Settings Sync VSCode设置同步到Gist
有时候我们到了新公司或者换了新电脑需要配置新的开发环境,这时候一个一个下载插件,再重新配置vs code就非常麻烦而且你还不一定记得那么全面,通过这个插件我们可以将当前vs code中的配置上传到Gist,之后再通过Gist下载,就可以将所有配置同步到新环境中了。
在Github首页点击头像,选择Settings进入设置页面。
点击左侧侧边栏Developer settings,进入开发者设置。
选择Personal access tokens,点击右侧Generate new token。
填写token名称,在下方勾选gist。
点击下方的Generate token按钮生成一个新的token。
将生成的新的token保存下来。
在vscode中安装Settings Sync插件,输入Ctrl+Shift+p输入Sync,选择更新/上传配置。
将github中生成的token输入,点击回车。
在控制台中自动生成一串id,之后便可以通过token和id进行配置同步。
输入Ctrl+Shift+p输入Sync,选择下载配置,输入token和id即可同步下载。
这篇文章中介绍的vs code配置已经全部同步到Gist,有需要的小伙伴可以下载一下。
token:b3c5f29c0e6f9f49b23b44ce89467226cd91c9c6
Id:338d5dfb6b7784c980250cffe8365899
可以在配置文件中选择是否自动上传和下载
"sync.removeExtensions": true,
"sync.syncExtensions": true,
"sync.autoDownload": true,
"sync.autoUpload": true,
"sync.gist": "338d5dfb6b7784c980250cffe8365899"
颜色主题
作为一名程序员,每天大部分时间都是坐在电脑前敲代码,需要长时间的跟编辑器打交道,为我们的vscode选择一款好看的颜色主题,能极大地提升写代码过程中的愉悦感,为了保护眼睛,这里推荐一个深色主题安装包,里面包含了如下几款皮肤。
我个人最喜欢的还是下面两款深色主题,主题这个东西一般用习惯了也不会来回去换,所以选择一款自己用着舒服的就好。
Dracula Official 吸血鬼主题(本人目前使用的一款)
One Dark Pro
常用快捷键
编辑器与窗口管理
Ctrl+Shift+P: 打开命令面板。
Ctrl+Shift+N: 新建窗口。
Ctrl+Shift+W: 关闭窗口。
切分窗口:Ctrl+1/Ctrl+3/Ctrl+3
Ctrl+H:最小化窗口
Ctrl+B:显示/隐藏侧边栏
Ctrl+"+/-":放大/缩小界面
文件操作
Ctrl+N:新建文件
Ctrl+W:关闭文件
Ctrl+Tab:文件切换
格式调整
Ctrl+C/Ctrl+V:复制或剪切当前行/当前选中内容
Alt+Up/Down:向上/下移动一行
Shift+Alt+Up//Down:向上/下复制一行
Ctrl+Delete:删除当前行
Shift+Alt+Left/Right:从光标开始向左/右选择内容
代码编辑
Ctrl+D:选中下一个相同内容
Ctrl+Shift+L:选中所有相同内容
Ctrl+F:查找内容
Ctrl+Shit+F:在整个文件夹中查找内容
常用设置
我们可以在settings.json中手动进行一些设置,让我们的编辑器更好用。
关闭标签介绍信息
我们在编写代码的时候鼠标移动到某个标签上,经常会自动弹出一些介绍信息,挡住部分代码,给我们的阅读带来了很大的困难,一直没有找到关闭它的方法,目前可以通过设置时间延迟暂时实现这个效果,我设置的5000毫秒,你可以设置的更大一些,基本上它就不会弹出来了。
"editor.hover.delay": 5000
自动折行
设置代码根据编辑器窗口大小自动折行
"editor.wordWrap": "on"
字体设置
// 一款适合代码显示的字体包(需要将字体包下载到本地)
"editor.fontFamily": "Source Code Pro, 'Source Code Pro'",
// 设置代码字体大小
"editor.fontSize": 15,
自动保存
目前有四个选项:
- off:关闭自动保存。
- afterDelay:当文件修改后的时间超过"Files:Auto Save Delay"中配置的值时自动进行保存。
- onFocusChange:编辑器失去焦点时自动保存更新后的文件。
- onWindowChange:窗口失去焦点时自动保存更新后的文件。
"files.autoSave": "off"
关闭代码提示
"editor.quickSuggestions": { "other": false, "comments": false, "strings": false }
推荐阅读
-
搞定VS Code Python环境全攻略:一篇满足你的深度设置教程
-
这样设置 VS Code,超级提升你的工作效率!
-
你的VS Code设置真的让你用着顺心吗?
-
这样设置 VS Code,超级提升你的工作效率!
-
这样设置 VS Code,超级提升你的工作效率!
-
反传销网8月30日发布:视频区块链里的骗子,币里的韭菜,杜子建骂人了!金融大V周召说区块链!——“一小帮骗子玩一大帮小白,被割韭菜,小白还轮流被割,割的就是你!” 什么区块链,统统是骗子 作者:周召(知乎金融领域大V,毕业于上海财经大学,目前任职上海某股权投资基金合伙人) 有人问我,区块链现在这么火,到底是不是骗局? 我的回答是: 是骗局。而且我并不是说数字货币是骗局,而是说所有搞区块链的都是骗局。 -01- 区块链是一种鸡肋技术 人类社会任何技术的发明应用,本质都是为了提高社会的生产效率。而所谓区块链技术本质不过是几种早已成熟的技术的大杂烩,冗余且十分低效,除了提高了洗钱和诈骗的效率以外,对人类社会的进步毫无贡献。 真正意义上的区块链得包含三个要素:分布式系统(包括记账和存储),无法篡改的数据结构,以及共识算法,三者互为基础和因果,就像三体世界一样。看上去挺让人不明觉厉的,而经过几年的瞎折腾,稍微懂点区块链的碰了几次壁后都已经渐渐明白区块链其实并没有什么卵用,区块链技术已经名存实亡,沦为了营销工具和传销组织的画皮。 因为符合上述定义的、以比特币为代表的原教旨区块链技术,是反效率的,从经济学角度来说,不但不是一种帕累托改进,甚至还可以说是一种帕累托倒退。 原教旨区块链技术的效率十分低下,因为要遍历所有节点,只能做非常轻量级的数据应用,一旦涉及到大量的数据传输与更新,区块链就瞎了。 一方面整条链交易速度会极慢,另一方面数据库容量极速膨胀,考虑到人手一份的存储机制,区块链其实是对存储资源和能源的一种极大的浪费。 这里还没有加上为了取得所谓的共识和挖矿消耗的巨大的能源,如果说区块链技术是屎,那么这波区块链投机浪潮可谓人类历史上最大规模的搅屎运动。 区块链也验证不了任何东西。 所谓的智能合约,即不智能,也非合约。我看有人还说,如果有了智能合约,就可以跟老板签一份放区块链上,如果明年销售业绩提升30%,就加薪10%,由于区块链不能篡改,不能抵赖,所以老板必须得执行,说得有板有眼,不懂行的愣一看,好像还真是那么回事。 但仔细一想,问题就来了。首先,在区块链上如何证明你真的达到了30%业绩提升?即便真的达到老板耍赖如何执行? 也就是说,如果区块链真这么厉害,要法院和仲裁干什么。 人类社会真正的符合成本效益原则的是代理制度。之前有人说要用区块链改造注册会计师行业,我不知道他准备怎么设计,我猜想他思路大概是这样的,首先肯定搞去中心化,让所有会计师到链上来,然后一个新人要成为注册会计师就要所有会计师同意并记录在链上。 那我就请问了,我每天上班累死累活,为什么还要花时间去验证一个跟我无关的的人的专业能力?最优做法当然是组织一个委员会,让专门的人来负责,这不就是现在注册会师协会干的事儿吗?区块链的逻辑相当于什么事情都要拿出来公投,这个绝对是扯淡的。 当然这么说都有点抬举区块链了,区块链技术本身根本没有判断是非能力,如果这么高级的人工智能,靠一个无脑分布式记账就能实现的话,我们早就进入共产主义社会了。 虽然EOS等数字货币采用了超级节点,通过再中心化的方式提高效率,有点行业协会的意思,是对区块链原教旨主义的一种修正,但是依然无法突破区块链技术最本质的局限性。有人说,私有链和联盟链是区块链技术的未来,也是扯淡,因为区块链技术没有未来。如果有,说明他是包装成区块链的伪区块链技术。 区块链所涉及的所有底层技术,不管是分布式数据库技术,加密技术,还是点对点传输技术等,基本都是早已存在没什么秘密可言的技术。 比特币系统最重要的特性是封闭性和自洽性,他验证不了任何系统自身以外产生的信息的真实性。 所谓系统自身产生的信息,就是数据库数据的变动信息,有价值的基本上有且只有交易信息。所以说比特币最初不过是中本聪一种炫技的产物,来证明自己对几种技术的掌握,你看我多牛逼,设计出了一个像三体一样的系统。因此,数字货币很有可能是区块链从始至终唯一的杀手应用。 比特币和区块链概念从诞生到今天已经快10年了,很多人说区块链技术在爆发的前夜,但这个前夜好像是不是有点过长了啊朋友,跟三体里的长夜有一拼啊。都说区块链技术像是90年代初的互联网,可是90年代初的互联网在十年发展后,已经出现了一大批伟大的公司,阿里巴巴在99年都成立了,区块链怎么除了币还是币呢? 正规的数字货币未来发展的形式无外乎几种,要么就是论坛币形式,或者类似股票的权益凭证等。问题是论坛币和股票之前,本来也都电子化了,区块链来了到底改变了什么呢? 所有想把TOKEN和应用场景结合起来的人最后都很痛苦,最后他们会发现区块链技术就是脱裤子放屁,自己辛苦搞半天,干嘛不自己作为中心关心门来收钱?最后这些人都产生了价值的虚无感,最终精神崩溃,只能发币疯狂收割韭菜,一边嘴里还说着我是个好人之类的奇怪的话。 因此,之前币圈链圈还泾渭分明,互相瞧不起,但这两年链圈逐渐坐不住了,想着是不是趁着泡沫没彻底破灭之前赶快收割一波,不然可能什么都捞不着了。 前段时间和一个名校毕业的链圈朋友瞎聊天,他说他们“致力于用区块链技术解决数字版权保护问题”,我就问他一个问题,你们如何保证你链的版权所有权声明是真实的,万一盗版者抢先一步把数据放在链上怎么办。他说他们的解决方案是连入国家数字版权保护中心的数据库进行验证…… 所以说区块链技术就是个鸡肋,研究到最后都会落入效率与真实性的黑洞,很多人一头扎进链圈后才发现,真正意义上的区块链技术,其实什么都干不了。 -02- 不是蠢就是坏的区块链媒体 空气币和区块链的造富神话,让区块链自媒体也开始迎风乱扭。一群群根本不知道区块链为何物的妖魔鬼怪纷纷进驻区块链自媒体战场,开始大放厥词胡编乱造。 任何东西,但凡只要和区块,链,分,分布式,记账,加密,验证,可追溯等等这些个关键词沾到哪怕一点点,这些所谓的区块链媒体人就会像狗闻到了屎了一样疯狂地把区块链概念往上套。 这让我想起曾经一度也是热闹非凡的物联网,我曾经去看过江苏一家号称要改变世界的“物联网”企业,过去一看是生产路由器的,我黑人问号脸,对方解释说没有路由器万物怎么互联,我觉得他说得好有道理,竟无言以对。 好,下面让我们进入奇葩共赏析时间,来看看区城链媒体经常有哪些危言耸听的奇谈怪论 区块链(分布式记账)的典型应用是*?? 正如前面所说,真正意义上的区块链分布式记账,不光包括“记”这个动作,还包括分布式存储和共识机制等。而*诞生远远早于区块链这个词的出现,勉强算是“分布式编辑”吧,就被很多区块链媒体拿来强行充当区块链技术应用的典范。 其实事实恰恰相反,*恰恰是去中心化失败的典范,现在如果没有精英和专业人士的编辑和维护,*早就没法看了。 区块链会促进社会分工?? 罗振宇好像就说过类似的话,虽然罗振宇说过很多没有逻辑的话,但这句话绝对是最没逻辑思维的。很多区块链自媒体也常常用这句话来忽悠老百姓,说分工代表效率提高社会进步,而区块链“无疑”会促进分工,他们的理由仅仅是分工和分布式记账都共用一个“分”字,就强行把他们扯到一起。 实际情况恰恰相反,区块链是逆分工的,区块链精神是号召所有人积极地参与到他不擅长也不想掺合的事情里面去。 区块链不能像上帝一样许诺他的子民死后上天国,只能给他们许诺你们是六度人脉中的第一级,我可以赚后面五级人的钱,你处于金字塔的顶端。
-
在Neovim中设置本地的Clangd配置来提升你的工作效率
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面