2018年9月

Steam 的新实验功能允许你在 Linux 上玩仅限 Windows 的游戏。以下是如何在 Steam 中使用此功能。

你已经听说过这个消息。游戏发行平台 Steam 正在复刻一个 WINE 分支来允许你玩仅限于 Windows 上的游戏。对于 Linux 用户来说,这绝对是一个好消息,因为我们总抱怨 Linux 的游戏数量不足。

这个新功能仍处于测试阶段,但你现在可以在 Linux 上试用它并在 Linux 上玩仅限 Windows 的游戏。让我们看看如何做到这一点。

使用 Steam Play 在 Linux 中玩仅限 Windows 的游戏

Play Windows-only games on Linux

你需要先安装 Steam。Steam 适用于所有主要 Linux 发行版。我已经详细介绍了在 Ubuntu 上安装 Steam,如果你还没有安装 Steam,你可以参考那篇文章。

安装了 Steam 并且你已登录到 Steam 帐户,就可以了解如何在 Steam Linux 客户端中启用 Windows 游戏。

步骤 1:进入帐户设置

运行 Steam 客户端。在左上角,单击 “Steam”,然后单击 “Settings”。

Enable steam play beta on Linux

步骤 2:选择加入测试计划

在“Settings”中,从左侧窗口中选择“Account”,然后单击 “Beta participation” 下的 “CHANGE” 按钮。

Enable beta feature in Steam Linux

你应该在此处选择 “Steam Beta Update”。

Enable beta feature in Steam Linux

在此处保存设置后,Steam 将重新启动并下载新的测试版更新。

步骤 3:启用 Steam Play 测试版

下载好 Steam 新的测试版更新后,它将重新启动。到这里就差不多了。

再次进入“Settings”。你现在可以在左侧窗口看到新的 “Steam Play” 选项。单击它并选中复选框:

  • Enable Steam Play for supported titles (你可以玩列入白名单的 Windows 游戏)
  • Enable Steam Play for all titles (你可以尝试玩所有仅限 Windows 的游戏)

Play Windows games on Linux using Steam Play

我不记得 Steam 是否会再次重启,但我想这无所谓。你现在应该可以在 Linux 上看到安装仅限 Windows 的游戏的选项了。

比如,我的 Steam 库中有《Age of Empires》,正常情况下这个在 Linux 中没有。但我在 Steam Play 测试版启用所有 Windows 游戏后,现在我可以选择在 Linux 上安装《Age of Empires》了。

Install Windows-only games on Linux using Steam

现在可以在 Linux 上安装仅限 Windows 的游戏

有关 Steam Play 测试版功能的信息

在 Linux 上使用 Steam Play 测试版玩仅限 Windows 的游戏有一些事情你需要知道并且牢记。

我希望本教程能帮助你在 Linux 上运行仅限 Windows 的游戏。你期待在 Linux 上玩哪些游戏?


via: https://itsfoss.com/steam-play/

作者:Abhishek Prakash 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

想要在 Linux 命令行工作中提高效率,你需要使用一些技巧。

巧妙的 Linux 命令行技巧能让你节省时间、避免出错,还能让你记住和复用各种复杂的命令,专注在需要做的事情本身,而不是你要怎么做。以下介绍一些好用的命令行技巧。

命令编辑

如果要对一个已输入的命令进行修改,可以使用 ^actrl + a)或 ^ectrl + e)将光标快速移动到命令的开头或命令的末尾。

还可以使用 ^ 字符实现对上一个命令的文本替换并重新执行命令,例如 ^before^after^ 相当于把上一个命令中的 before 替换为 after 然后重新执行一次。

$ eho hello world  <== 错误的命令

Command 'eho' not found, did you mean:

 command 'echo' from deb coreutils
 command 'who' from deb coreutils

Try: sudo apt install <deb name>

$ ^e^ec^        <== 替换
echo hello world
hello world

使用远程机器的名称登录到机器上

如果使用命令行登录其它机器上,可以考虑添加别名。在别名中,可以填入需要登录的用户名(与本地系统上的用户名可能相同,也可能不同)以及远程机器的登录信息。例如使用 server_name ='ssh -v -l username IP-address' 这样的别名命令:

$ alias butterfly=”ssh -v -l jdoe 192.168.0.11”

也可以通过在 /etc/hosts 文件中添加记录或者在 DNS 服务器中加入解析记录来把 IP 地址替换成易记的机器名称。

执行 alias 命令可以列出机器上已有的别名。

$ alias
alias butterfly='ssh -v -l jdoe 192.168.0.11'
alias c='clear'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias list_repos='grep ^[^#] /etc/apt/sources.list /etc/apt/sources.list.d/*'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias show_dimensions='xdpyinfo | grep '\''dimensions:'\'''

只要将新的别名添加到 ~/.bashrc 或类似的文件中,就可以让别名在每次登录后都能立即生效。

冻结、解冻终端界面

^sctrl + s)将通过执行流量控制命令 XOFF 来停止终端输出内容,这会对 PuTTY 会话和桌面终端窗口产生影响。如果误输入了这个命令,可以使用 ^qctrl + q)让终端重新响应。所以只需要记住 ^q 这个组合键就可以了,毕竟这种情况并不多见。

复用命令

Linux 提供了很多让用户复用命令的方法,其核心是通过历史缓冲区收集执行过的命令。复用命令的最简单方法是输入 ! 然后接最近使用过的命令的开头字母;当然也可以按键盘上的向上箭头,直到看到要复用的命令,然后按回车键。还可以先使用 history 显示命令历史,然后输入 ! 后面再接命令历史记录中需要复用的命令旁边的数字。

!! <== 复用上一条命令
!ec <== 复用上一条以 “ec” 开头的命令
!76 <== 复用命令历史中的 76 号命令

查看日志文件并动态显示更新内容

使用形如 tail -f /var/log/syslog 的命令可以查看指定的日志文件,并动态显示文件中增加的内容,需要监控向日志文件中追加内容的的事件时相当有用。这个命令会输出文件内容的末尾部分,并逐渐显示新增的内容。

$ tail -f /var/log/auth.log
Sep 17 09:41:01 fly CRON[8071]: pam_unix(cron:session): session closed for user smmsp
Sep 17 09:45:01 fly CRON[8115]: pam_unix(cron:session): session opened for user root
Sep 17 09:45:01 fly CRON[8115]: pam_unix(cron:session): session closed for user root
Sep 17 09:47:00 fly sshd[8124]: Accepted password for shs from 192.168.0.22 port 47792
Sep 17 09:47:00 fly sshd[8124]: pam_unix(sshd:session): session opened for user shs by
Sep 17 09:47:00 fly systemd-logind[776]: New session 215 of user shs.
Sep 17 09:55:01 fly CRON[8208]: pam_unix(cron:session): session opened for user root
Sep 17 09:55:01 fly CRON[8208]: pam_unix(cron:session): session closed for user root
        <== 等待显示追加的内容

寻求帮助

对于大多数 Linux 命令,都可以通过在输入命令后加上选项 --help 来获得这个命令的作用、用法以及它的一些相关信息。除了 man 命令之外, --help 选项可以让你在不使用所有扩展选项的情况下获取到所需要的内容。

$ mkdir --help
Usage: mkdir [OPTION]... DIRECTORY...
Create the DIRECTORY(ies), if they do not already exist.

Mandatory arguments to long options are mandatory for short options too.
 -m, --mode=MODE set file mode (as in chmod), not a=rwx - umask
 -p, --parents no error if existing, make parent directories as needed
 -v, --verbose print a message for each created directory
 -Z set SELinux security context of each created directory
 to the default type
 --context[=CTX] like -Z, or if CTX is specified then set the SELinux
 or SMACK security context to CTX
 --help display this help and exit
 --version output version information and exit

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
Full documentation at: <http://www.gnu.org/software/coreutils/mkdir>
or available locally via: info '(coreutils) mkdir invocation'

谨慎删除文件

如果要谨慎使用 rm 命令,可以为它设置一个别名,在删除文件之前需要进行确认才能删除。有些系统管理员会默认使用这个别名,对于这种情况,你可能需要看看下一个技巧。

$ rm -i    <== 请求确认

关闭别名

你可以使用 unalias 命令以交互方式禁用别名。它不会更改别名的配置,而仅仅是暂时禁用,直到下次登录或重新设置了这一个别名才会重新生效。

$ unalias rm

如果已经将 rm -i 默认设置为 rm 的别名,但你希望在删除文件之前不必进行确认,则可以将 unalias 命令放在一个启动文件(例如 ~/.bashrc)中。

使用 sudo

如果你经常在只有 root 用户才能执行的命令前忘记使用 sudo,这里有两个方法可以解决。一是利用命令历史记录,可以使用 sudo !!(使用 !! 来运行最近的命令,并在前面添加 sudo)来重复执行,二是设置一些附加了所需 sudo 的命令别名。

$ alias update=’sudo apt update’

更复杂的技巧

有时命令行技巧并不仅仅是一个别名。毕竟,别名能帮你做的只有替换命令以及增加一些命令参数,节省了输入的时间。但如果需要比别名更复杂功能,可以通过编写脚本、向 .bashrc 或其他启动文件添加函数来实现。例如,下面这个函数会在创建一个目录后进入到这个目录下。在设置完毕后,执行 source .bashrc,就可以使用 md temp 这样的命令来创建目录立即进入这个目录下。

md () { mkdir -p "$@" && cd "$1"; }

总结

使用 Linux 命令行是在 Linux 系统上工作最有效也最有趣的方法,但配合命令行技巧和巧妙的别名可以让你获得更好的体验。


via: https://www.networkworld.com/article/3305811/linux/linux-tricks-that-even-you-can-love.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

检查你的代码的质量,通过这些外部库使其更易维护。

可读性很重要。
Python 之禅 The Zen of Python ,Tim Peters

随着软件项目进入“维护模式”,对可读性和编码标准的要求很容易落空(甚至从一开始就没有建立过那些标准)。然而,在代码库中保持一致的代码风格和测试标准能够显著减轻维护的压力,也能确保新的开发者能够快速了解项目的情况,同时能更好地全程保持应用程序的质量。

使用外部库来检查代码的质量不失为保护项目未来可维护性的一个好方法。以下会推荐一些我们最喜爱的检查代码)(包括检查 PEP 8 和其它代码风格错误)的库,用它们来强制保持代码风格一致,并确保在项目成熟时有一个可接受的测试覆盖率。

检查你的代码风格

PEP 8 是 Python 代码风格规范,它规定了类似行长度、缩进、多行表达式、变量命名约定等内容。尽管你的团队自身可能也会有稍微不同于 PEP 8 的代码风格规范,但任何代码风格规范的目标都是在代码库中强制实施一致的标准,使代码的可读性更强、更易于维护。下面三个库就可以用来帮助你美化代码。

1、 Pylint

Pylint 是一个检查违反 PEP 8 规范和常见错误的库。它在一些流行的编辑器和 IDE 中都有集成,也可以单独从命令行运行。

执行 pip install pylint 安装 Pylint 。然后运行 pylint [options] path/to/dir 或者 pylint [options] path/to/module.py 就可以在命令行中使用 Pylint,它会向控制台输出代码中违反规范和出现错误的地方。

你还可以使用 pylintrc 配置文件来自定义 Pylint 对哪些代码错误进行检查。

2、 Flake8

Flake8 是“将 PEP 8、Pyflakes(类似 Pylint)、McCabe(代码复杂性检查器)和第三方插件整合到一起,以检查 Python 代码风格和质量的一个 Python 工具”。

执行 pip install flake8 安装 flake8 ,然后执行 flake8 [options] path/to/dir 或者 flake8 [options] path/to/module.py 可以查看报出的错误和警告。

和 Pylint 类似,Flake8 允许通过配置文件来自定义检查的内容。它有非常清晰的文档,包括一些有用的提交钩子,可以将自动检查代码纳入到开发工作流程之中。

Flake8 也可以集成到一些流行的编辑器和 IDE 当中,但在文档中并没有详细说明。要将 Flake8 集成到喜欢的编辑器或 IDE 中,可以搜索插件(例如 Sublime Text 的 Flake8 插件)。

3、 Isort

Isort 这个库能将你在项目中导入的库按字母顺序排序,并将其正确划分为不同部分(例如标准库、第三方库、自建的库等)。这样提高了代码的可读性,并且可以在导入的库较多的时候轻松找到各个库。

执行 pip install isort 安装 isort,然后执行 isort path/to/module.py 就可以运行了。文档中还提供了更多的配置项,例如通过配置 .isort.cfg 文件来决定 isort 如何处理一个库的多行导入。

和 Flake8、Pylint 一样,isort 也提供了将其与流行的编辑器和 IDE 集成的插件。

分享你的代码风格

每次文件发生变动之后都用命令行手动检查代码是一件痛苦的事,你可能也不太喜欢通过运行 IDE 中某个插件来实现这个功能。同样地,你的同事可能会用不同的代码检查方式,也许他们的编辑器中也没有那种插件,甚至你自己可能也不会严格检查代码和按照警告来更正代码。总之,你分享出来的代码库将会逐渐地变得混乱且难以阅读。

一个很好的解决方案是使用一个库,自动将代码按照 PEP 8 规范进行格式化。我们推荐的三个库都有不同的自定义级别来控制如何格式化代码。其中有一些设置较为特殊,例如 Pylint 和 Flake8 ,你需要先行测试,看看是否有你无法忍受但又不能修改的默认配置。

4、 Autopep8

Autopep8 可以自动格式化指定的模块中的代码,包括重新缩进行、修复缩进、删除多余的空格,并重构常见的比较错误(例如布尔值和 None 值)。你可以查看文档中完整的更正列表

运行 pip install --upgrade autopep8 安装 Autopep8。然后执行 autopep8 --in-place --aggressive --aggressive <filename> 就可以重新格式化你的代码。aggressive 选项的数量表示 Auotopep8 在代码风格控制上有多少控制权。在这里可以详细了解 aggressive 选项。

5、 Yapf

Yapf 是另一种有自己的配置项列表的重新格式化代码的工具。它与 Autopep8 的不同之处在于它不仅会指出代码中违反 PEP 8 规范的地方,还会对没有违反 PEP 8 但代码风格不一致的地方重新格式化,旨在令代码的可读性更强。

执行 pip install yapf 安装 Yapf,然后执行 yapf [options] path/to/diryapf [options] path/to/module.py 可以对代码重新格式化。定制选项的完整列表在这里。

6、 Black

Black 在代码检查工具当中算是比较新的一个。它与 Autopep8 和 Yapf 类似,但限制较多,没有太多的自定义选项。这样的好处是你不需要去决定使用怎么样的代码风格,让 Black 来给你做决定就好。你可以在这里查阅 Black 有限的自定义选项以及如何在配置文件中对其进行设置

Black 依赖于 Python 3.6+,但它可以格式化用 Python 2 编写的代码。执行 pip install black 安装 Black,然后执行 black path/to/dirblack path/to/module.py 就可以使用 Black 优化你的代码。

检查你的测试覆盖率

如果你正在进行编写测试,你需要确保提交到代码库的新代码都已经测试通过,并且不会降低测试覆盖率。虽然测试覆盖率不是衡量测试有效性和充分性的唯一指标,但它是确保项目遵循基本测试标准的一种方法。对于计算测试覆盖率,我们推荐使用 Coverage 这个库。

7、 Coverage

Coverage 有数种显示测试覆盖率的方式,包括将结果输出到控制台或 HTML 页面,并指出哪些具体哪些地方没有被覆盖到。你可以通过配置文件自定义 Coverage 检查的内容,让你更方便使用。

执行 pip install coverage 安装 Converage 。然后执行 coverage [path/to/module.py] [args] 可以运行程序并查看输出结果。如果要查看哪些代码行没有被覆盖,执行 coverage report -m 即可。

持续集成工具

持续集成 Continuous integration (CI)是在合并和部署代码之前自动检查代码风格错误和测试覆盖率最小值的过程。很多免费或付费的工具都可以用于执行这项工作,具体的过程不在本文中赘述,但 CI 过程是令代码更易读和更易维护的重要步骤,关于这一部分可以参考 Travis CIJenkins

以上这些只是用于检查 Python 代码的各种工具中的其中几个。如果你有其它喜爱的工具,欢迎在评论中分享。


via: https://opensource.com/article/18/7/7-python-libraries-more-maintainable-code

作者:Jeff Triplett 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

APT, 是 Advanced Package Tool 的缩写,是基于 Debian 的系统的默认包管理器。我们可以使用 APT 安装、更新、升级和删除应用程序。最近,我一直遇到一个奇怪的错误。每当我尝试更新我的 Ubuntu 16.04 时,我都会收到此错误 - “0% [Connecting to in.archive.ubuntu.com (2001:67c:1560:8001::14)]” ,同时更新流程会卡住很长时间。我的网络连接没问题,我可以 ping 通所有网站,包括 Ubuntu 官方网站。在搜索了一番谷歌后,我意识到 Ubuntu 镜像站点有时无法通过 IPv6 访问。在我强制将 APT 包管理器在更新系统时使用 IPv4 代替 IPv6 访问 Ubuntu 镜像站点后,此问题得以解决。如果你遇到过此错误,可以按照以下说明解决。

强制 APT 包管理器在 Ubuntu 16.04 中使用 IPv4

要在更新和升级 Ubuntu 16.04 LTS 系统时强制 APT 使用 IPv4 代替 IPv6,只需使用以下命令:

$ sudo apt-get -o Acquire::ForceIPv4=true update
$ sudo apt-get -o Acquire::ForceIPv4=true upgrade

瞧!这次更新很快就完成了。

你还可以使用以下命令在 /etc/apt/apt.conf.d/99force-ipv4 中添加以下行,以便将来对所有 apt-get 事务保持持久性:

$ echo 'Acquire::ForceIPv4 "true";' | sudo tee /etc/apt/apt.conf.d/99force-ipv4

免责声明:

我不知道最近是否有人遇到这个问题,但我今天在我的 Ubuntu 16.04 LTS 虚拟机中遇到了至少四、五次这样的错误,我按照上面的说法解决了这个问题。我不确定这是推荐的解决方案。请浏览 Ubuntu 论坛来确保此方法合法。由于我只是一个 VM,我只将它用于测试和学习目的,我不介意这种方法的真实性。请自行承担使用风险。

希望这有帮助。还有更多的好东西。敬请关注!

干杯!


via: https://www.ostechnix.com/how-to-force-apt-package-manager-to-use-ipv4-in-ubuntu-16-04/

作者:SK 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在这篇文章中,我将讨论为什么你需要尝试一下 Go 语言,以及应该从哪里学起。

Go 语言是可能是最近几年里你经常听人说起的编程语言。尽管它在 2009 年已经发布了,但它最近才开始流行起来。

根据 Google 趋势,Go 语言非常流行。

这篇文章不会讨论一些你经常看到的 Go 语言的主要特性。

相反,我想向您介绍一些相当小众但仍然很重要的功能。只有在您决定尝试 Go 语言后,您才会知道这些功能。

这些都是表面上没有体现出来的惊人特性,但它们可以为您节省数周或数月的工作量。而且这些特性还可以使软件开发更加愉快。

阅读本文不需要任何语言经验,所以不必担心你还不了解 Go 语言。如果你想了解更多,可以看看我在底部列出的一些额外的链接。

我们将讨论以下主题:

  • GoDoc
  • 静态代码分析
  • 内置的测试和分析框架
  • 竞争条件检测
  • 学习曲线
  • 反射
  • Opinionatedness
  • 文化

请注意,这个列表不遵循任何特定顺序来讨论。

GoDoc

Go 语言非常重视代码中的文档,所以也很简洁。

GoDoc 是一个静态代码分析工具,可以直接从代码中创建漂亮的文档页面。GoDoc 的一个显著特点是它不使用任何其他的语言,如 JavaDoc、PHPDoc 或 JSDoc 来注释代码中的结构,只需要用英语。

它使用从代码中获取的尽可能多的信息来概述、构造和格式化文档。它有多而全的功能,比如:交叉引用、代码示例,并直接链接到你的版本控制系统仓库。

而你需要做的只有添加一些像 // MyFunc transforms Foo into Bar 这样子的老牌注释,而这些注释也会反映在的文档中。你甚至可以添加一些通过网络界面或者在本地可以实际运行的 代码示例

GoDoc 是 Go 的唯一文档引擎,整个社区都在使用。这意味着用 Go 编写的每个库或应用程序都具有相同的文档格式。从长远来看,它可以帮你在浏览这些文档时节省大量时间。

例如,这是我最近一个小项目的 GoDoc 页面:pullkee — GoDoc

静态代码分析

Go 严重依赖于静态代码分析。例如用于文档的 godoc,用于代码格式化的 gofmt,用于代码风格的 golint,等等。

它们是如此之多,甚至有一个总揽了它们的项目 gometalinter ,将它们组合成了单一的实用程序。

这些工具通常作为独立的命令行应用程序实现,并可轻松与任何编码环境集成。

静态代码分析实际上并不是现代编程的新概念,但是 Go 将其带入了绝对的范畴。我无法估量它为我节省了多少时间。此外,它给你一种安全感,就像有人在你背后支持你一样。

创建自己的分析器非常简单,因为 Go 有专门的内置包来解析和加工 Go 源码。

你可以从这个链接中了解到更多相关内容: GothamGo Kickoff Meetup: Alan Donovan 的 Go 静态分析工具

内置的测试和分析框架

您是否曾尝试为一个从头开始的 JavaScript 项目选择测试框架?如果是这样,你或许会理解经历这种 过度分析 analysis paralysis 的痛苦。您可能也意识到您没有使用其中 80% 的框架。

一旦您需要进行一些可靠的分析,问题就会重复出现。

Go 附带内置测试工具,旨在简化和提高效率。它为您提供了最简单的 API,并做出最小的假设。您可以将它用于不同类型的测试、分析,甚至可以提供可执行代码示例。

它可以开箱即用地生成便于持续集成的输出,而且它的用法很简单,只需运行 go test。当然,它还支持高级功能,如并行运行测试,跳过标记代码,以及其他更多功能。

竞争条件检测

您可能已经听说了 Goroutine,它们在 Go 中用于实现并发代码执行。如果你未曾了解过,这里有一个非常简短的解释。

无论具体技术如何,复杂应用中的并发编程都不容易,部分原因在于竞争条件的可能性。

简单地说,当几个并发操作以不可预测的顺序完成时,竞争条件就会发生。它可能会导致大量的错误,特别难以追查。如果你曾经花了一天时间调试集成测试,该测试仅在大约 80% 的执行中起作用?这可能是竞争条件引起的。

总而言之,在 Go 中非常重视并发编程,幸运的是,我们有一个强大的工具来捕捉这些竞争条件。它完全集成到 Go 的工具链中。

您可以在这里阅读更多相关信息并了解如何使用它:介绍 Go 中的竞争条件检测 - Go Blog

学习曲线

您可以在一个晚上学习所有的 Go 语言功能。我是认真的。当然,还有标准库,以及不同的,更具体领域的最佳实践。但是两个小时就足以让你自信地编写一个简单的 HTTP 服务器或命令行应用程序。

Go 语言拥有出色的文档,大部分高级主题已经在他们的博客上进行了介绍:Go 编程语言博客

比起 Java(以及 Java 家族的语言)、Javascript、Ruby、Python 甚至 PHP,你可以更轻松地把 Go 语言带到你的团队中。由于环境易于设置,您的团队在完成第一个生产代码之前需要进行的投资要小得多。

反射

代码反射本质上是一种隐藏在编译器下并访问有关语言结构的各种元信息的能力,例如变量或函数。

鉴于 Go 是一种静态类型语言,当涉及更松散类型的抽象编程时,它会受到许多各种限制。特别是与 Javascript 或 Python 等语言相比。

此外,Go 没有实现一个名为泛型的概念,这使得以抽象方式处理多种类型更具挑战性。然而,由于泛型带来的复杂程度,许多人认为不实现泛型对语言实际上是有益的。我完全同意。

根据 Go 的理念(这是一个单独的主题),您应该努力不要过度设计您的解决方案。这也适用于动态类型编程。尽可能坚持使用静态类型,并在确切知道要处理的类型时使用 接口 interface 。接口在 Go 中非常强大且无处不在。

但是,仍然存在一些情况,你无法知道你处理的数据类型。一个很好的例子是 JSON。您可以在应用程序中来回转换所有类型的数据。字符串、缓冲区、各种数字、嵌套结构等。

为了解决这个问题,您需要一个工具来检查运行时的数据并根据其类型和结构采取不同行为。 反射 Reflect 可以帮到你。Go 拥有一流的反射包,使您的代码能够像 Javascript 这样的语言一样动态。

一个重要的警告是知道你使用它所带来的代价 —— 并且只有知道在没有更简单的方法时才使用它。

你可以在这里阅读更多相关信息: 反射的法则 — Go 博客.

您还可以在此处阅读 JSON 包源码中的一些实际代码: src/encoding/json/encode.go — Source Code

Opinionatedness(专制独裁的 Go)

顺便问一下,有这样一个单词吗?

来自 Javascript 世界,我面临的最艰巨的困难之一是决定我需要使用哪些约定和工具。我应该如何设计代码?我应该使用什么测试库?我该怎么设计结构?我应该依赖哪些编程范例和方法?

这有时候基本上让我卡住了。我需要花时间思考这些事情而不是编写代码并满足用户。

首先,我应该注意到我完全知道这些惯例的来源,它总是来源于你或者你的团队。无论如何,即使是一群经验丰富的 Javascript 开发人员也很容易发现他们在实现相同的结果时,而大部分的经验却是在完全不同的工具和范例上。

这导致整个团队中出现过度分析,并且使得个体之间更难以相互协作。

嗯,Go 是不同的。即使您对如何构建和维护代码有很多强烈的意见,例如:如何命名,要遵循哪些结构模式,如何更好地实现并发。但你只有一个每个人都遵循的风格指南。你只有一个内置在基本工具链中的测试框架。

虽然这似乎过于严格,但它为您和您的团队节省了大量时间。当你写代码时,受一点限制实际上是一件好事。在构建新代码时,它为您提供了一种更直接的方法,并且可以更容易地调试现有代码。

因此,大多数 Go 项目在代码方面看起来非常相似。

文化

人们说,每当你学习一门新的口语时,你也会沉浸在说这种语言的人的某些文化中。因此,您学习的语言越多,您可能会有更多的变化。

编程语言也是如此。无论您将来如何应用新的编程语言,它总能给你带来新的编程视角或某些特别的技术。

无论是函数式编程, 模式匹配 pattern matching 还是 原型继承 prototypal inheritance 。一旦你学会了它们,你就可以随身携带这些编程思想,这扩展了你作为软件开发人员所拥有的问题解决工具集。它们也改变了你阅读高质量代码的方式。

而 Go 在这方面有一项了不起的财富。Go 文化的主要支柱是保持简单,脚踏实地的代码,而不会产生许多冗余的抽象概念,并将可维护性放在首位。大部分时间花费在代码的编写工作上,而不是在修补工具和环境或者选择不同的实现方式上,这也是 Go 文化的一部分。

Go 文化也可以总结为:“应当只用一种方法去做一件事”。

一点注意事项。当你需要构建相对复杂的抽象代码时,Go 通常会妨碍你。好吧,我会说这是简单的权衡。

如果你真的需要编写大量具有复杂关系的抽象代码,那么最好使用 Java 或 Python 等语言。然而,这种情况却很少。

在工作时始终使用最好的工具!

总结

你或许之前听说过 Go,或者它暂时在你圈子以外的地方。但无论怎样,在开始新项目或改进现有项目时,Go 可能是您或您团队的一个非常不错的选择。

这不是 Go 的所有惊人的优点的完整列表,只是一些被人低估的特性。

请尝试一下从 Go 之旅 来开始学习 Go,这将是一个令人惊叹的开始。

如果您想了解有关 Go 的优点的更多信息,可以查看以下链接:

并在评论中分享您的阅读感悟!

即使您不是为了专门寻找新的编程语言语言,也值得花一两个小时来感受它。也许它对你来说可能会变得非常有用。

不断为您的工作寻找最好的工具!

题图来自 https://github.com/ashleymcnamara/gophers 的图稿


via: https://medium.freecodecamp.org/here-are-some-amazing-advantages-of-go-that-you-dont-hear-much-about-1af99de3b23a

作者:Kirill Rogovoy 译者:imquanquan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux DNS 查询剖析(第一部分)Linux DNS 查询剖析(第二部分)Linux DNS 查询剖析(第三部分) 中,我们已经介绍了以下内容:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • pinghost 查询方式的对比
  • systemd 和对应的 networking 服务
  • ifupifdown
  • dhclient
  • resolvconf
  • NetworkManager
  • dnsmasq

在第四部分中,我将介绍容器如何完成 DNS 查询。你想的没错,也不是那么简单。

1) Docker 和 DNS

Linux DNS 查询剖析(第三部分) 中,我们介绍了 dnsmasq,其工作方式如下:将 DNS 查询指向到 localhost 地址 127.0.0.1,同时启动一个进程监听 53 端口并处理查询请求。

在按上述方式配置 DNS 的主机上,如果运行了一个 Docker 容器,容器内的 /etc/resolv.conf 文件会是怎样的呢?

我们来动手试验一下吧。

按照默认 Docker 创建流程,可以看到如下的默认输出:

$  docker run  ubuntu cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.

search home
nameserver 8.8.8.8
nameserver 8.8.4.4

奇怪!

地址 8.8.8.88.8.4.4 从何而来呢?

当我思考容器内的 /etc/resolv.conf 配置时,我的第一反应是继承主机的 /etc/resolv.conf。但只要稍微进一步分析,就会发现这样并不总是有效的。

如果在主机上配置了 dnsmasq,那么 /etc/resolv.conf 文件总会指向 127.0.0.1 这个 回环地址 loopback address 。如果这个地址被容器继承,容器会在其本身的 网络上下文 networking context 中使用;由于容器内并没有运行(在 127.0.0.1 地址的)DNS 服务器,因此 DNS 查询都会失败。

“有了!”你可能有了新主意:将 主机的 的 IP 地址用作 DNS 服务器地址,其中这个 IP 地址可以从容器的 默认路由 default route 中获取:

root@79a95170e679:/# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2

使用主机 IP 地址真的可行吗?

从默认路由中,我们可以找到主机的 IP 地址 172.17.0.1,进而可以通过手动指定 DNS 服务器的方式进行测试(你也可以更新 /etc/resolv.conf 文件并使用 ping 进行测试;但我觉得这里很适合介绍新的 dig 工具及其 @ 参数,后者用于指定需要查询的 DNS 服务器地址):

root@79a95170e679:/# dig @172.17.0.1 google.com | grep -A1 ANSWER.SECTION
;; ANSWER SECTION:
google.com.             112     IN      A       172.217.23.14

但是还有一个问题,这种方式仅适用于主机配置了 dnsmasq 的情况;如果主机没有配置 dnsmasq,主机上并不存在用于查询的 DNS 服务器。

在这个问题上,Docker 的解决方案是忽略所有可能的复杂情况,即无论主机中使用什么 DNS 服务器,容器内都使用 Google 的 DNS 服务器 8.8.8.88.8.4.4 完成 DNS 查询。

我的经历:在 2013 年,我遇到了使用 Docker 以来的第一个问题,与 Docker 的这种 DNS 解决方案密切相关。我们公司的网络屏蔽了 8.8.8.88.8.4.4,导致容器无法解析域名。

这就是 Docker 容器的情况,但对于包括 Kubernetes 在内的容器 编排引擎 orchestrators ,情况又有些不同。

2) Kubernetes 和 DNS

在 Kubernetes 中,最小部署单元是 pod;它是一组相互协作的容器,共享 IP 地址(和其它资源)。

Kubernetes 面临的一个额外的挑战是,将 Kubernetes 服务请求(例如,myservice.kubernetes.io)通过对应的 解析器 resolver ,转发到具体服务地址对应的 内网地址 private network 。这里提到的服务地址被称为归属于“ 集群域 cluster domain ”。集群域可由管理员配置,根据配置可以是 cluster.localmyorg.badger 等。

在 Kubernetes 中,你可以为 pod 指定如下四种 pod 内 DNS 查询的方式。

Default

在这种(名称容易让人误解)的方式中,pod 与其所在的主机采用相同的 DNS 查询路径,与前面介绍的主机 DNS 查询一致。我们说这种方式的名称容易让人误解,因为该方式并不是默认选项!ClusterFirst 才是默认选项。

如果你希望覆盖 /etc/resolv.conf 中的条目,你可以添加到 kubelet 的配置中。

ClusterFirst

ClusterFirst 方式中,遇到 DNS 查询请求会做有选择的转发。根据配置的不同,有以下两种方式:

第一种方式配置相对古老但更简明,即采用一个规则:如果请求的域名不是集群域的子域,那么将其转发到 pod 所在的主机。

第二种方式相对新一些,你可以在内部 DNS 中配置选择性转发。

下面给出示例配置并从 Kubernetes 文档中选取一张图说明流程:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"acme.local": ["1.2.3.4"]}
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]

stubDomains 条目中,可以为特定域名指定特定的 DNS 服务器;而 upstreamNameservers 条目则给出,待查询域名不是集群域子域情况下用到的 DNS 服务器。

这是通过在一个 pod 中运行我们熟知的 dnsmasq 实现的。

kubedns

剩下两种选项都比较小众:

ClusterFirstWithHostNet

适用于 pod 使用主机网络的情况,例如绕开 Docker 网络配置,直接使用与 pod 对应主机相同的网络。

None

None 意味着不改变 DNS,但强制要求你在 pod 规范文件 specification dnsConfig 条目中指定 DNS 配置。

CoreDNS 即将到来

除了上面提到的那些,一旦 CoreDNS 取代 Kubernetes 中的 kube-dns,情况还会发生变化。CoreDNS 相比 kube-dns 具有可配置性更高、效率更高等优势。

如果想了解更多,参考这里

如果你对 OpenShift 的网络感兴趣,我曾写过一篇文章可供你参考。但文章中 OpenShift 的版本是 3.6,可能有些过时。

第四部分总结

第四部分到此结束,其中我们介绍了:

  • Docker DNS 查询
  • Kubernetes DNS 查询
  • 选择性转发(子域不转发)
  • kube-dns

via: https://zwischenzugs.com/2018/08/06/anatomy-of-a-linux-dns-lookup-part-iv/

作者:zwischenzugs 译者:pinewall 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出