Go 语言中奇怪的 if 语句

上篇文章提到过 Go 语言中带有强烈的设计者的主观想法,Go 的 if 语句就是其中一例

常见的 if 语句大约是这个样子的(C++):

这样有一个问题:变量 event 定义在了 if 语句的外面,也就是说,在 if 语句之后,也可以继续使用 event 变量;而如果后续的操作中不需要 event 变量了,它实际上就造成了命名空间的污染。这并不是一个严重的问题,多数情况下不会造成任何问题,而如果一定要解决的话,在 C++ 中可以在 event 的定义之外套一层大括号来限定它的作用域。虽然代码看上去有一些奇怪,但无伤大雅。比如这样:

但是 Go 的设计者不知是出于什么原因,非要从语法上解决这个问题。于是 Go 中的 if 语句可以写成这个样子:

对,你没有看错。虽然 event 是定义在了 if 中,但它在 else 中也是可以用的。也就是说,这种写法实际上是上述的 C++ 写法的语法糖。

并不清楚 Go 的设计者添加这个语法糖的目的是什么。它仅仅是为了解决变量的作用域问题而提出,却牺牲了代码的可读性。if 语句可能会变得过长而不易阅读;在后续重构的过程中,拆分 if 语句也会变得困难。为了解决一个小问题而增加一种有问题的语法,看上去有点得不尝失。

吐槽一下 Go 语言

由于公司一直都在大力推广 Go 语言,我也有幸接触了一下。虽然 Google 内部已有三大语言(C++、Java、Python),Go 在公司内部的政治意义大于它的实际使用,但它的设计却有着很多亮点。比如 Go 自带了代码格式化工具(gofmt)和自动化测试工具(go test),这些标准化的工作在其它语言中一直都存在着多方争议,一直都不能统一,而 Go 从一开始就搞定了这些琐碎问题,让广大程序员可以把重心都放在开发新程序上,而不是争一些有的没的。

当然,这篇文章并不想表扬 Go 语言,而是要吐槽一下它的缺点。

Go 的设计者有着强烈的 Unix 背景,有一些平台依赖的东西都默认甚至是强制成 Unix 的。比如 Go 语言中有一个名为“path”的包,用来操作路径,而它强制路径分隔符为“/”,而无视 Windows 中的“\”。后来估计是开发中遇到一些问题,又做了一个叫“filepath”的包,来兼容 Windows 的使用。又比如 Go 语言中对环境变量的解析,强制环境变量的标识符为“$”,而不视 Windows 中的“%”,甚至整个标准库中都找不到对“%”的处理方法。这些基本的区别都不做处理,很难想象 Go 语言在跨平台设计中有哪些更为隐藏的坑。

这还不是主要的问题。更严重的问题是,Go 语言中有过多的“私有”特性,对使用者不公平。

先来举一个 C++ 的例子,C++ 中有一些运算符,比如加减乘除,这些运算符可以使用于 C++ 的基础类型(如 int)上。基础类型是 C++ 语言本身提供的,如果运算符只能作用于基础类型,那么 C++ 也可被视为“自私”的。然而 C++ 的设计者并没有这么做,这些运算符,不仅可以用于基础类型,也可以在自定义类型中,通过重载的方式来使用,使得 C++ 中不仅两个 int 可以相加,两个 class 的实例也可以相加。这样一来,运算符对于使用者就是公平的。

而 Go 语言中,则有着很多反例。比如它的泛型:Go 的官方说法是“我们不支持泛型”,具体原因就不深入讨论了。但是,Go 语言的自有类型 map 和 channel 却是支持泛型的。这就成了一个典型的“自私”的例子。类似的例子还有 Go 语言中的 internal 包有着特殊的作用域;Go 的官方库有着极短的包名,而第三方库通常是以“github”开头的很长一串文本。

这些“私有”特性,说明 Go 语言的设计者并没有为开发人员考虑过,自己设计得爽了,却徒增了学习曲线,不利于 Go 语言的推广。如果能把这些问题解决好,Go 还是可以成为一门不错的语言的。

电视剧播放模式即将被颠覆

这几天闹得沸沸扬扬的《芈月传》全集泄漏事件,着实让这部不怎么样的电视剧再火了一把。要泄漏一定得有内鬼,而版权方貌似对这个内鬼一点办法都没有,只能去谴责百度,因为百度云盘提供了部分影片的下载。后来百度乖乖地把涉事的文件全给删了。

这件事从一个侧面说明,百度云盘会监控用户的文件,涉及隐私的文件请不要传上百度云。

当然本文的重点不是这个。这里我们来关注一下泄漏事件的必然性。

大概二十年前,电视机成为了家家户户必不可少的娱乐设备。它不仅是一块屏幕,而是所有电视节目的入口。电视节目无论大小,上到每年一次的春晚,下到每天三十分钟的新闻,都要从这个几十寸或方或扁的盒子里观看。每天晚上全家围坐在电视机前嗑瓜子,也逐渐成为了常态。

有线电视业务也因此火暴了起来,全国有数百个电视台,每个电视台自负盈亏,为了利润不惜动用各种龌龊手段。就拿电视剧而言,本来是在电视剧中插播广告,现在是在广告中插播电视剧;而一部电视剧,每天只播一集两集,甚至有些一周才播一集,吊人胃口,让人不得不每天每周按时看电视。

而好景不长,也就十几年的功夫,互联网彻底改变了这一切。

在线看视频,和电视台有相当的不同。一是互联网视频随看随播,想什么时候看就什么时候看,想看哪一集就看哪一集,不怕因故错过了一集而连不下去;二是广告少,各种视频网站都可以通过加入会员,或者其它工具的方式,把广告取消,不必在广告中找寻电视节目;三是想在哪看就在哪看,冬天天冷不必待在客厅挨冻,抱个笔记本窝在被子里也可以流畅观看。就因为这几点,有线电视业务近几年迅速缩水,不得不在广电总局的庇护下才可以苟延。

正是有了互联网视频,电视机又做回了它的老本行:一块屏幕。

而在线视频的大杀器,则是全集一起上线。由于用户可以自由地选择想看的节目,互联网视频不再受限于播放渠道,相当于每个用户都有一个专属的电视台。只要网站的节目足够多,就可以吸引用户停留更多的时间,而不用像传统的电视台那样,用每天一集的方式来让用户回归。于是越来越多的网络剧,选择了一次放出所有剧集的方式,让大家一次看个够。实际上,虽然可以自由支配时间,用户每天花在娱乐上的时间也是有限的,即使有全集可以看,也不是所有用户都会一次性看完。于是在线视频就用更吸引人的方式,做了和电视台差不多的事情。

《芈月传》泄漏事件之所以火暴,还不是因为广大网民不能忍受每天两集的龟速。每个人都有自由支配自己时间的权力,那个大锅饭统一管理的年代已经一去不复返了。

在 Markdown 中设置链接由新窗口打开

尽管我对 Markdown 不是那么感冒,但工作和生活中总是难免会使用到一些,比如在向某些开源项目发 PR 的时候。于是对 Markdown 的一些小技巧也有所了解。

Markdown 中的链接语法是这样的:[文本](链接)。它相当于 HTML 中的

但众所周知,HTML 的 a 标签有一个实用的属性 target,当它的值为“_blank”的时候,浏览器会默认为这个链接打开一个新窗口,而不是在当前页面转向新页面。而 Markdown 中没有这个“_blank”选项,于是所有链接都只能在当前页面打开,有些情况会非常不方便。

在多数 Markdown 解释器中(如 GitHub Flavored Markdown),这个情况无解。如果一个 Markdown 解释器同时支持 HTML 语法,则这种情况可以通过直接写 HTML 解决。

于是我又多了一个不喜欢 Markdown 的理由。

上线了三台 CDN 服务器

我对 KeyCDN 的服务感到非常失望,它家的缓存算法和缓存服务器速度都存在相当多的问题,导致本博客基本上每次访问都会回源,反而增加了加载时间。为了提高全球访客的浏览体验,本博客新增了三台 CDN 服务器,分别位于比利时、美国爱荷华州和中国台湾。

CDN 服务器会缓存所有的博客页面,直到页面有更新,比如新增博文或评论,才会刷新。这样做相当于做了全站静态化,并把静态页面事先加载到三个主要的大洲。世界各地的来访请求,会被 Google Cloud 的负载平衡引擎导向最近的静态页面,使得加载时间降到最低。距离 CDN 服务器较近的用户,可以获得小于 100ms 的页面下载时间。

目前由于价格的原因,图片资源依然放在 KeyCDN。Google Cloud 的 CDN 项目正在内测中,明年年初公测之后,如果价格合适,就会全部转向 Google Cloud。

有兴趣的同学们,欢迎测速 :)

WordPress 4.4

WordPress 4.4 在这个月初发布了。由于 WordPress 的新版本质量有下滑的趋势,本来我想等 4.4.1 发布了再升级。后来去翻阅了一下 4.4 的新功能列表,发现没什么特别多的新功能。于是就升掉了,目前看来没有什么大问题。

WordPress 4.4 的一个主要改动是图片会根据访客的屏幕大小而自动适配,不至于图片过大而引起整体布局混乱。不过本站的图片都是我手动修改过大小的,本来就不会产生这样的问题,升级之后也看不出有什么变化。就当它不存在吧。

新功能没什么用就算了,WordPress 又强推了一些本身就没什么用的功能,而且默认开启。

其一是 JSON REST API,这是一个编程操作的接口,是面向第三方工具的。对于普通用户来说,实际上是一个看不见摸不着的功能。由于它非常得新,现在还没什么工具能用得上这个接口。而且新功能多少会带来一些安全隐患,在它没有被反复论证之前,我暂时没什么兴趣让这个接口一直开着。关闭的方法如下,在主题或 functions.php 中添加:

其二是 WordPress 这段时间在大力完善的功能:oEmbed。这个功能的作用是,比如博文中嵌入了一条 YouTube 的链接,本来它只会显示成一条文本链接,但有了 oEmbed 之后,WordPress 会把这个链接自动变成 YouTube 视频,在博文中播放出来。说这个功能没用,是因为一来我一般不在文章中贴视频或者其它外来的东西,二来 oEmbed 支持的都是国外网站,即使转成了视频,国内的访客多数也看不到。

oEmbed 这个功能一直以来都很老实,只是在后台默默地转换链接而已,不过在 4.4 中,它终于跳到了前台。WordPress 4.4 中默认添加了一个 js 引用:wp-embed.min.js。于是我就不爽了,一定要把这个功能给关了。关闭方法如下:

好了,这下终于舒服舒服地用上 WordPress 4.4 了。

iPhone 6s 省电设置

我把 4s 时代的省电方法用在了 6s 上面,结果是我的 iPhone 6s Plus 不充电的情况下可以正常使用至少三天。一到家就插充电线的情况就此离我远去了。

接下来介绍一下省电的经验:

关闭通知

几乎每个应用都会有通知(Notification),从应用的角度来说,它肯定希望多发一些通知来引起你的注意,以便经常打开那个应用;而从我们用户的角度来说,大多数通知是没有意义的,通知多了不仅令人烦躁,还大量地消耗电力。

关闭的方法如下:

  1. 打开“设置 -> 通知”,会看到一排应用列表;
  2. 对于不必要应用,点进去把“允许通知”关闭即可。

我只保留了一些必要功能的通知,比如短信和 Facetime,而 90% 的应用通知都被我关闭了。

仅在应用中使用位置服务

iOS 的位置服务(Location Service)有三种权限设定:永不(Never)、使用应用程序期间(While Using)、始终(Always)。由于 iOS 的伪多线程机制,一个应用在不显示的时候,实际上处于挂起状态。于是把权限设为“当使用时”可以避免位置服务一直处于开启状态,以节省电量。

设置方法:

  1. 打开“设置 -> 隐私 -> 位置服务”,会看到一排应用列表;
  2. 对于每一个应用,点进去选择“使用应用程序期间”;
  3. 如果这个应用不支持“使用应用程序期间”,我一般会设成“永不”。

关闭后台程序刷新

iOS 允许应用程序在后台挂起的同时,做一些必要的工作,比如音乐应用在后台下载歌曲等。然而并不是所有的应用都有必要在后台运行。对于那些我们并不关心的应用,大可把“后台程序刷新”给关了。

设置方法:

  1. 打开“设置 -> 通用 -> 后台程序刷新”,会看到一排应用列表;
  2. 对于大多数应用,都可以把这项功能关闭;

我只保留了一些必要的应用,比如 Google Photos(后台上传照片)、Google Calendar(刷新日程)等,90% 的应用都关闭了后台刷新。需要注意的是,这项功能对新应用是默认开启的,所以过一段时间之后,还要回来看看,把那些新安装的应用也关掉。

关闭 Siri

个人经验,Siri 除了偶尔调戏一下之外,并不会经常使用,但它启用的状态下,却一直在消耗电力。

设置方法:

  1. 打开“设置 -> 通用 -> Siri”;
  2. 把 Siri 整体关闭;

关闭 iCloud 备份

在最新 iOS 中,照片已经有了单独的一项,称为“iCloud 照片库”,而之前的“iCloud 备份”只是用来备份一些应用程序设置和数据。而我从来都没有用到过这些备份,每次换新的 iPhone 都是设置为全新的 iPhone 而不是从备份中恢复。于是这些备份所占用的空间和备份时使用的电量,对我来说是完完全全的浪费。

设置方法:

  1. 打开“设置 -> iCloud”;
  2. 找到“备份(Backup)”;
  3. 点进去把它关闭;

总结

以上这些设置可以让 iPhone 4s 在用了三年之后,还可以待机一天左右。而 iPhone 6s 的电量是 4s 的大约两倍,并且性能上有很大的提升,于是待机三天不成问题。