Luyu Huang's Tech Blog

Printing parameters in Lua traceback

When an error occurs, Lua will print a traceback of the call stack, it helps us to find bugs. In many cases, however, a call stack traceback is not enough for us to find out the problem. We need more information, such as the environment, parameters of each function call, even all local variables of the stack. I decide to modify Lua to improve t...

Read more

Lua 夏令时时区问题

我之前的一篇文章介绍了怎样在服务器和客户端之间同步时间和时区. 同步时间相对简单些, 本质就是一个时间差; 而时区相对复杂些. 那篇文章介绍的方法有一个问题: 在客户端的时区启用了夏令时的时候, 客户端得到的本地时间会比实际快一个小时. 原因是求客户端时区的方法不对. 例如, 太平洋时区本为 UTC-0800, 而当客户端处于太平洋时区的 2020 年 10 月 29 日, 此时太平洋时区启用夏令时, 时区应为 UTC-0700. 如果使用这样的方法 local now = os_time() local CLIENT_TIMEZONE = math.floor(os.difftime(now, os_time(os_date("!*t", now)))) 求得的时区 CLIEN...

Read more

Lua next 函数的一个有趣问题

熟悉 Lua 的同学都知道, Lua 是允许在 for ... pairs 循环中修改和删除表中元素的. 下面这样的代码是没有任何问题的: local t = {a = 1, b = 2, c = 3} for k, v in pairs(t) do if v == 1 then t[k] = nil end end 但是, 如果我们在遍历时既删除元素又新增元素, 就会有问题了. 比如说: local t = {a = 1, b = 2, c = 3} for k, v in pairs(t) do if v == 1 then t[k] = nil t[k .. 1] = v + 1 end en...

Read more

A simple way to turn callback pattern to coroutine pattern in Lua

My game project is written by Lua. However, its framework does not provide a coroutine pattern, it uses a simple callback pattern instead. For example, to send an http request and receive the response, you must write like this: http_get("https://luyuhuang.tech/sitemap.xml", function(code, content) if code ~= 200 then print("an error...

Read more

全排列问题

给定 n 个不同的元素, 问有多少种不同的排列方式. 这就是全排列问题. 我们高中时就学过排列公式 $A_n^m = \frac{n!}{(n-m)!}$, 因此对于 n 个元素, 全排列数等于 $A_n^n = \frac{n!}{(n-n)!} = n!$ . 例如对于序列 [1, 2, 3] 全排列为 [1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1] 共 $3! = 6$ 种. 这里我们讨论 Leetcode 上的三道全排列问题. 1. 全排列 题目源自 Leetcode 46 题 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ ...

Read more

只出现一次的数字

这里分享三道寻找数组中只出现一次的数字的问题. 这些题使用哈希表都很好做, 但这里我们使用位运算, 可以很巧妙地在常数空间复杂度内解决问题. 第一题 题目源自 Leetcode 136 题 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 说明: 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 示例 1: 输入: [2,2,1] 输出: 1 示例 2: 输入: [4,1,2,1,2] 输出: 4 异或运算的特性是, 异为真同为假. 即 1 ^ 1 = 0, 0 ^ 0 = 0, 1 ^ 0 = 1, 0 ^ 1 = 1. 因此, 两个相同的数异或的结果...

Read more

[翻译] RFC 1928: SOCKS 协议第 5 版

socks5 是一个常用的代理协议, 它既可以用来代理 TCP, 也可以代理 UDP. socks5 的用途非常广泛, 许多网络软件都支持 socks5, 主流操作系统也支持使用 socks5 作系统代理. RFC 1928 是 socks5 协议的规范文档, 本文是对 RFC 1928 的翻译. 原文见 RFC 1928 - SOCKS Protocol Version 5. 以下是翻译正文: 文档声明 本文档为互联网社区规范了一个互联网标准跟踪的协议, 并征求讨论和改进建议. 请参阅当前版本的 "互联网官方协议标准(STD 1)" 以获取此协议的标准化的状态. 本文档的发布不受限制. 致谢 本文描述的协议是其之前版本 (第 4 版) [1] 的升级版. 该协议离不开积极的...

Read more

Y-Combinator: 如何在匿名函数中递归调用自身

如何实现一个阶乘函数? 最简单的做法是使用递归: 'use strict'; function factorial(n) { if (n === 0) { return 1; } else { return n * factorial(n - 1); } } 很好. 那么如何将 factorial 函数写成一个匿名函数, 且同样递归调用自身呢? (arguments.callee 禁止) 答案略显诡异. 它是这样的: 1 2 3 4 5 6 7 8 9 10 11 'use strict'; const Y = (F) => ((g) => g(g))((g) => F((x) => g(g)...

Read more