主页

Golang常量声明中的隐式重复与iota

Go语言中批量声明常量时,除了第一个常量外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面第一个非空表达式常量的初始化表达式及其类型(如果有的话),标识符的数量必须等于上一个列表中的表达式的数量,这个特性被称作“隐式重复(implicit repetition)”。

如果只是简单地复制右边的常量表达式,其实并没有太实用的价值。但是它可以带来其它的特性,那就是iota常量生成器语法。

看下面的例子:

1
2
3
4
5
const (
    a = iota
    b = iota
    c = iota
)

阅读更多

Go modules镜像代理服务-goproxy.io

goproxy.io是 Go modules 镜像代理服务,采用 CDN 加速服务为开发者提供依赖下载。可以解决国内用户下载Go依赖时的经常遇到的timeout问题,省去了翻墙的麻烦,并且由于采用了CDN,下载速度很快。实乃Go语言开发者必备服务。

使用方法很简单:

Go 版本1.13 及以上 (推荐)

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
# 设置不走 proxy 的私有仓库,多个用逗号相隔(可选)
go env -w GOPRIVATE=*.corp.example.com

设置完上面几个环境变量后,您的 go 命令将从公共代理镜像中快速拉取您所需的依赖代码了。

阅读更多

Shell中按指定分隔符读取文件字段

在很多情况下我们要对文本文件进行读取操作,Shell中读取文件的方法有很多种。比如简单的按行读取:

#!/bin/bash

for line in `cat file.txt`
do
    echo $line
done

每一次循环会读入一行文件内容放入$line变量中。

另外一种情况下,我们要读取像csv类似的文件,每行的字段按指定的分隔符分隔,该如何处理呢? 可以利用IFS环境变量来指定分隔符并用read命令来读取各个字段。

阅读更多

《代码之美》-- 正则表达式

在《代码之美》一书中,作者展示了一段大约30行的C代码,实现了一个正则表达式匹配器。

该正则表达式提供了如下匹配模型:

字符 含义
c 匹配任意字母c
. 匹配任意单个字符
^ 匹配输入字符串的开头
$ 匹配输入字符串的结尾
. 匹配前一个字符的零个或多个出现

这是非常有用的匹配器,基本上可以解决95%左右的正则匹配问题。这段代码写的紧凑 、优雅、高效并且实用。这段代码充分展示了c指针的强大功能,以及递归的极佳示例。

你可以自己动手实现一下上面的功能,然后再来对比一下书中这段代码,看看是否也能实现的如此精简高效。

阅读更多

博客更换域名

之前用了很久的博客域名: linuxsong.org,用的是aws国外的服务器,在国内访问速度实在是太慢了,于是想切回到阿里云,但是近来org的域名现在已经不允许备案了。没办法只好申请了一个新的域名: topbyte.cn, 服务器换成了阿里云的。

从今天开始启用新的域名,之前的linuxsong.org以后会暂停使用了。

阅读更多

Linus Torvalds 提及的关于代码的"good taste"

在一个关于 Linus Torvalds 的一个访谈中, Linus Torvalds 举了一个关于什么是代码好的品味的例子(视频14:20左右)。

他先是展示了一个C代码片断。

poor taste code example

这段代码的作用是删除链表中的一个节点, Linus 认为这不是一段具有好品味的代码。原因是循环后面的 if 判断,删除链表节点时需要考虑两种不同的情况,一种是删除的是链表的head节点,另外一种是删除的中间节点或者尾部节点。

接下来, Linus 又展示了另外一段具有好品味的代码,和上面的一段代码实现的是同样的功能。

阅读更多

A*算法的JavaScript实现

A* (A-Star)算法是一种路径搜索和图形遍历算法,它有较好的性能和准确度。

A*的算法公式:f(n) = g(n) + h(n)

f(n)是节点n的综合优先级。当我们选择下一个要遍历的节点时,我们总会选取综合优先级最高(值最小)的节点。g(n) 是节点n距离起点的代价。h(n)是节点n距离终点的预计代价,这也就是A*算法的启发函数。

A*算法在运算过程中,每次从优先队列中选取f(n)值最小(优先级最高)的节点作为下一个待遍历的节点。

另外,A*算法使用两个集合来表示待遍历的节点,与已经遍历过的节点,这通常称之为open_set和close_set。

完整的算法描述如下:

* 初始化open_set和close_set;
* 将起点加入open_set中,并设置优先级为0(优先级最高);
* 如果open_set不为空,则从open_set中选取优先级最高的节点n:
    * 如果节点n为终点,则:
        * 从终点开始逐步追踪parent节点,一直达到起点;
        * 返回找到的结果路径,算法结束;
    * 如果节点n不是终点,则:
        * 将节点n从open_set中删除,并加入close_set中;
        * 遍历节点n所有的邻近节点:
            * 如果邻近节点m在close_set中,则:
                * 跳过,选取下一个邻近节点
            * 如果邻近节点m也不在open_set中,则:
                * 设置节点m的parent为节点n
                * 计算节点m的优先级
                * 将节点m加入open_set中

根据上面的算法描述,用js实现了一个算法演示。

阅读更多