<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[KurisuRakko]]></title><description><![CDATA[A product-minded engineer building interfaces, workflows, and tiny autonomous systems.]]></description><link>https://rakko.cn</link><image><url>https://rakko.cn/favicon.ico</url><title>KurisuRakko</title><link>https://rakko.cn</link></image><generator>Yohaku (https://github.com/Innei/Yohaku)</generator><lastBuildDate>Sat, 17 Oct 2026 03:44:20 GMT</lastBuildDate><atom:link href="https://rakko.cn/feed" rel="self" type="application/rss+xml"/><pubDate>Sat, 17 Oct 2026 03:44:19 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[COMP1531 W3L1 现场 Demo 笔记]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/comp1511/1531w3l1demo">https://rakko.cn/posts/comp1511/1531w3l1demo</a></blockquote><div><blockquote><p>视频：<a href="https://www.youtube.com/watch?v=agTr-VqsO_g">COMP1531 Week 3 Lecture 1</a>（2026-09-29，约 1:50）
来源：本地 ASR 转写 + 视频截帧整理，<strong>非官方材料</strong>，细节以视频和 spec 为准。时间均为视频时间，点链接直接跳转。</p></blockquote>
<p>本讲两位讲师：前半节 Rani Jiang 讲 Iteration 1，并用 <code>clearData</code> 演示一个 feature 的完整流程；后半节讲 Dynamic Verification 和 Code Coverage。</p><ul><li>0:24:59–0:30:51 是现场 debug，可以跳过。</li><li>0:53:30–1:04:20 是课间休息。</li></ul><hr/><h2 id="demo-0---sample-0042000535httpsyoutubeagtr-vqsogt260">Demo 0 · 前端 sample 演示（<a href="https://youtu.be/agTr-VqsO_g?t=260">0:04:20–0:05:35</a>）</h2><ul><li>演示 tutor 写的终端界面（TUI）闪卡 app：新建卡片（Q: best CSE course / A: COMP1531），建 deck，再往 deck 里加卡。</li><li>讲师说这只是 sample，<strong>不是 reference solution</strong>，他们实现时也做了自己的假设。</li></ul><hr/><h2 id="demo-a---cleardata--feature-0144205028httpsyoutubeagtr-vqsogt882">Demo A · 用 <code>clearData</code> 走完一个 feature 的完整流程（<a href="https://youtu.be/agTr-VqsO_g?t=882">0:14:42–0:50:28</a>）</h2><ul><li><strong>0:14:44</strong>：合并 GitLab 上的 &quot;[Iteration 1] Updated Starter Code&quot; MR（不用 approve，有冲突就照常解决）</li><li><strong>0:15:52</strong>：在 Issue board 新建 work item <code>clearData</code>，打标签 core、critical、in progress，链接 spec，设 due date</li><li><strong>0:17:45</strong>：<code>git checkout -b iter1-clearData</code></li><li><strong>0:18:26</strong>：在 <code>interface.js</code> 写 stub：<code>clearData()</code> 返回 <code>{}</code>。<code>data</code> 对象是 <code>{cards: [], decks: [], studySessions: []}</code>；clearData 把三个数组都重置成 <code>[]</code>，然后 commit</li><li><strong>0:23:00</strong>：新建 <code>src/clearData.test.js</code>。测试按三类想：返回值、副作用、错误（clearData 没有错误情况）。第一个测试是 <code>test(&#x27;return value&#x27;, () =&gt; expect(clearData()).toStrictEqual({}))</code></li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=1499">0:24:59–0:30:51</a></strong>：<strong>现场 debug，可以跳过</strong>：报 vitest not found，接着是 <code>ERR_MODULE_NOT_FOUND</code>。最后的解法：<code>rm -rf node_modules</code>、删掉 <code>package-lock.json</code>、<code>npm cache clean --force</code>、<code>npm install</code></li><li><strong>0:32:31 / <a href="https://youtu.be/agTr-VqsO_g?t=2006">0:33:26</a></strong>：先讲 automarking 也会看 coverage，然后跑 <code>npm run coverage</code>。屏幕上 <code>interface.js</code> 是 Stmts 62.5%、Funcs 50%，未覆盖第 16–27 行</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2047">0:34:07</a></strong>：<strong>为什么要测副作用</strong>：把清空的代码注释掉，返回值测试照样能过。副作用测试的思路是 <code>cardsCreate</code> → <code>clearData</code> → <code>cardsView</code> 应该查不到；deck 同理</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2117">0:35:17</a></strong>：<strong>循环依赖</strong>：<code>cardsView</code>、<code>decksList</code> 队友还没写完怎么办？三种办法：先注释掉并在 MR 里写明、用 <code>test.todo(...)</code>、用 <code>test.skip(...)</code></li><li><strong>0:40:27</strong>：<code>git commit -m &quot;feat: add initial tests for clear&quot;</code></li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2489">0:41:29</a></strong>：<strong>重构拆文件</strong>：新建 <code>clearData.js</code>（放 <code>doClearData</code>），<code>interface.js</code> 里只写 <code>return doClearData()</code>；<code>data</code> 挪到 <code>dataStore.js</code> 里 export。重跑测试全部通过，有测试才敢放心重构。commit 是 <code>&quot;feat: refactor clear to be in separate file&quot;</code></li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2640">0:44:00</a></strong>：<code>git push --set-upstream origin iter1-clearData</code>，建 MR，标题带 issue 号（&quot;43 - clearData feature&quot;），assign 自己并加 reviewer。要不要删源分支问 tutor。之后队友 review、留评论、approve、merge，最后把 issue 拖到 closed</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2796">0:46:36</a></strong>：提交前检查：在 CSE 上跑 <code>1531 iter1-dryrun</code>，加 <code>--show-tests</code> 能看到测试内容。现场 dryrun 报错了，讲师说之后会修</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=2961">0:49:21</a></strong>：跑课程前端做 sanity check：报 <code>decksList failed: Not implemented</code>，现场补一个 stub 后又报下一个没实现的函数</li><li><strong>0:50:28</strong>：Q&amp;A：要不要一个函数一个文件？组里自己取舍，有理由就行</li></ul><h3 id="">要点</h3><ul><li>一个 feature 的完整流程：<strong>issue → branch → 实现 + 测试 → commit → push → MR → review → merge → 关 issue</strong>。</li><li>只测返回值不够，<strong>要测副作用</strong>。</li><li>依赖的函数还没写完时，用 <code>test.todo</code> / <code>test.skip</code> 先占位。</li><li><code>interface.js</code> 只负责转发，实现放在独立文件里，这样文件更整洁，也能减少 merge conflict。</li></ul><hr/><h2 id="demo-b----code-coverage1302914947httpsyoutubeagtr-vqsogt5429">Demo B · 动态验证 + Code Coverage（<a href="https://youtu.be/agTr-VqsO_g?t=5429">1:30:29–1:49:47</a>）</h2><p>代码在 GitLab 的 lecture 仓库 <code>3.1-Dynamic-Verification</code>，文件夹是 <code>2.4-dynamic-verification</code>。</p><ul><li><strong>1:32:02</strong>：回顾 <code>removeVowels.test.js</code> 的 import/export；clone 下来没有 <code>node_modules</code>，先 <code>npm install</code></li><li><strong>1:34:23</strong>：跑测试，代码里故意留的错误让测试失败，改好后通过</li><li><strong>1:35:20</strong>：<code>package.json</code> 的 scripts：<code>&quot;test&quot;: &quot;vitest run&quot;</code>、<code>&quot;coverage&quot;: &quot;vitest run --coverage&quot;</code>。对比 <code>npm test</code>（跑全部）和只跑单个文件</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=5784">1:36:24</a></strong>：<code>grade.js</code> 的 <code>computeGrade(mark)</code>：≥85 HD、≥75 DN、≥65 CR、≥50 PS，其余 FL</li><li><strong>1:37:24</strong>：删掉 DN 的测试，<strong>测试仍然全部通过</strong>，说明全绿不等于测全了</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=5944">1:39:04</a></strong>：加 <code>--coverage</code>：<code>grade.js</code> 是 Stmts 77.77%、Branch 75%、Funcs 100%，未覆盖第 7、13 行</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=6072">1:41:12</a></strong>：打开 <code>coverage/index.html</code> 网页报告，没覆盖的行会高亮</li><li><strong>1:42:11</strong>：补回 DN 测试后变成 88.88%、Branch 87.5%，只剩第 13 行（FL 分支）</li><li><strong>1:43:06</strong>：讨论：要盯着没覆盖的部分，而不是追百分比；branches 比 functions 更重要；一个函数一个文件对 coverage 没帮助</li><li><strong>1:46:40</strong>：一句话定义：dynamic verification 就是测输出是否符合预期</li><li><strong><a href="https://youtu.be/agTr-VqsO_g?t=6495">1:48:15</a></strong>：加 <code>test(&#x27;returns FL for below 50&#x27;)</code>，<code>computeGrade(45)</code> 应返回 <code>&#x27;FL&#x27;</code>（AI 补全的），到 1:49:40 达到 100%</li><li><strong>1:49:07</strong>：<strong>100% 覆盖仍然不够</strong>：负分和超过 100 的分数也会被接受，边界情况没测到</li></ul><h3 id="">要点</h3><ul><li>看 coverage 报告时，先看 <strong>Uncovered Line #s</strong> 和 HTML 报告里高亮的行，不要只盯着百分比。</li><li>Branch coverage 比 function coverage 更能说明问题。</li><li>覆盖率 100% 不代表测试足够，边界情况（edge cases）要另外考虑。</li></ul></div><p style="text-align:right"><a href="https://rakko.cn/posts/comp1511/1531w3l1demo#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/comp1511/1531w3l1demo</link><guid isPermaLink="true">https://rakko.cn/posts/comp1511/1531w3l1demo</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Fri, 02 Oct 2026 05:10:42 GMT</pubDate></item><item><title><![CDATA[COMP1521 Week 02 + Week 03 Check-off 突击卡]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/comp1511/w23coc">https://rakko.cn/posts/comp1511/w23coc</a></blockquote><div><p>来源：checkoff/02、checkoff/03 页（https://cgi.cse.unsw.edu.au/~cs1521/26T3/checkoff/02/questions 、/03/questions，Synced 2026-09-20 / 09-26）</p><p><strong>check-off 流程</strong>：tutor 在 lab 里走到你旁边，<strong>给你一段程序，陪你逐行过一遍，然后问几个问题</strong>；
过了会给你一个 access code，在 check-off 页面输入。其余 lab 题照常做。
你现在状态（student.md）：Week 01 = True 5/5，<strong>Week 02 = False，Week 03 = False</strong> → 今天 16:00 lab 两个都要做。
程序是 tutor 当场给的，没法提前背答案——要练的是「看一行 MIPS 能说出它干嘛」。</p><hr/><h2 id="1-week-02-">1. 看到一行就要能说出来（Week 02 核心）</h2><table><thead><tr><th> 写法 </th><th> 意思 </th><th> 用 C 说 </th></tr></thead><tbody><tr><td> <code>li $t0, 5</code> </td><td> 把常数 5 放进 $t0 </td><td> <code>t0 = 5</code> </td></tr><tr><td> <code>move $t1, $t0</code> </td><td> 复制寄存器 </td><td> <code>t1 = t0</code> </td></tr><tr><td> <code>add $t2, $t0, $t1</code> </td><td> 加 </td><td> <code>t2 = t0 + t1</code> </td></tr><tr><td> <code>addi $t0, $t0, 1</code> </td><td> 加常数 </td><td> <code>t0++</code> </td></tr><tr><td> <code>sub</code> / <code>mul</code> </td><td> 减 / 乘 </td><td> <code>-</code> / <code>*</code> </td></tr><tr><td> <code>div $t2, $t0, $t1</code> / <code>rem</code> </td><td> 整除 / 取余 </td><td> <code>/</code> / <code>%</code> </td></tr><tr><td> <code>la $t0, label</code> </td><td> 把 label 的<strong>地址</strong>放进来 </td><td> <code>t0 = &amp;label</code> </td></tr><tr><td> <code>lw $t1, 0($t0)</code> </td><td> 从地址 $t0 读 4 字节 </td><td> <code>t1 = *t0</code> </td></tr><tr><td> <code>sw $t1, 0($t0)</code> </td><td> 把 $t1 写到地址 $t0 </td><td> <code>*t0 = t1</code> </td></tr><tr><td> <code>b label</code> / <code>j label</code> </td><td> 无条件跳 </td><td> <code>goto</code> </td></tr><tr><td> <code>beq a, b, L</code> / <code>bne</code> </td><td> 相等 / 不等就跳 </td><td> <code>if (a == b) goto L</code> </td></tr><tr><td> <code>blt</code> <code>ble</code> <code>bgt</code> <code>bge</code> </td><td> &lt; ≤ &gt; ≥ 就跳 </td><td> </td></tr><tr><td> <code>beqz $t0, L</code> </td><td> 为 0 就跳 </td><td> <code>if (t0 == 0)</code> </td></tr><tr><td> <code>jal f</code> / <code>jr $ra</code> </td><td> 调函数 / 返回 </td><td> <code>f()</code> / <code>return</code> </td></tr></tbody></table><p><strong>syscall（先把编号放 $v0，参数放 $a0）</strong></p><table><thead><tr><th> $v0 </th><th> 作用 </th><th> 参数 / 结果 </th></tr></thead><tbody><tr><td> 1 </td><td> print int </td><td> $a0 = 要打的数 </td></tr><tr><td> 4 </td><td> print string </td><td> $a0 = 字符串地址（用 <code>la</code>） </td></tr><tr><td> 5 </td><td> read int </td><td> 读到的数在 <strong>$v0</strong> </td></tr><tr><td> 11 </td><td> print char </td><td> $a0 = 字符，如 <code>&#x27;\n&#x27;</code> </td></tr><tr><td> 10 </td><td> exit </td><td> — </td></tr></tbody></table><p><strong>寄存器</strong>：<code>$t0–$t9</code> 临时；<code>$s0–$s7</code> 函数调用后还要保住的；<code>$a0–$a3</code> 传参；<code>$v0</code> 返回值/syscall 号；
<code>$ra</code> 返回地址；<code>$sp</code> 栈顶；<code>$zero</code> 永远是 0。</p><h2 id="2-if--while--mipstutor-">2. if / while 怎么变成 MIPS（tutor 最爱问）</h2><p>口诀：<strong>条件取反，跳过去</strong>。</p><pre class=""><code class="">// C:  while (i &lt; 10) { ...; i++; }
loop:
    bge  $t0, 10, end     # i &gt;= 10 就跳出（把 &lt; 取反成 &gt;=）
    ...
    addi $t0, $t0, 1
    b    loop             # 回到开头再判
end:
</code></pre>
<pre class=""><code class="">// C:  if (x &gt; 5) { A } else { B }
    ble  $t0, 5, else     # x &lt;= 5 就去 else（&gt; 取反成 &lt;=）
    A
    b    endif            # 做完 A 必须跳过 B，否则会接着做 B
else:
    B
endif:
</code></pre>
<p>可能被问：「为什么是 bge 不是 blt？」→ 分支是&quot;满足就跳走&quot;，跳走的地方是循环外面，所以要写循环<strong>结束</strong>的条件（<code>i &lt; 10</code> 的反面 <code>i &gt;= 10</code>）。
「if 后面那个 <code>b endif</code> 删了会怎样？」→ A 做完会掉进 B，两个都执行。</p><h2 id="3---week-03-">3. 数组 / 内存（Week 03 核心）</h2><pre class=""><code class="">    .data
nums:   .word 3, 1, 4, 1, 5      # 5 个 int，已初始化
buf:    .space 40                # 40 字节 = 10 个 int，**未初始化（不保证是 0）**
msg:    .asciiz &quot;hi\n&quot;           # 字符串，自动加 &#x27;\0&#x27;
</code></pre>
<p><strong>第 i 个元素的地址 = 数组首地址 + i × 4</strong>（int 占 4 字节）</p><pre class=""><code class="">    la   $t1, nums        # t1 = &amp;nums[0]
    mul  $t2, $t0, 4      # t2 = i * 4        （也可以 sll $t2, $t0, 2）
    add  $t2, $t2, $t1    # t2 = &amp;nums[i]
    lw   $t3, 0($t2)      # t3 = nums[i]       （写回用 sw）
</code></pre>
<p>必背问答：</p><ul><li><strong>为什么乘 4？</strong> int 4 字节，地址按字节算。char 数组就乘 1，用 <code>lb</code>/<code>sb</code>。</li><li><strong><code>la</code> 和 <code>lw</code> 区别？</strong> <code>la</code> 拿地址（门牌号），<code>lw</code> 去那个地址把东西拿出来（屋里的东西）。</li><li><strong>忘了乘 4 会怎样？</strong> 读到错位的地址；<code>lw</code> 地址不是 4 的倍数会直接报 unaligned 错误。</li><li><strong><code>numbers[i-1]</code>？</strong> 地址再减 4，或写 <code>lw $t3, -4($t2)</code>（括号前的数字是字节偏移）。</li><li><strong>2D 数组 <code>a[r][c]</code>（每行 N 列）</strong>：地址 = 首地址 + (r × N + c) × 4。</li><li><strong>struct</strong>：每个字段在首地址上加固定偏移，<code>lw $t0, 4($t1)</code> = 取偏移 4 的那个字段。</li></ul><h2 id="4-week-3-lecture-2">4. 函数（Week 3 Lecture 2）</h2><ul><li>调用：参数放 <code>$a0..$a3</code>，<code>jal f</code>；返回值在 <code>$v0</code>。</li><li><code>jal</code> 会把&quot;回来的地址&quot;写进 <code>$ra</code>。<strong>函数里如果还要再 <code>jal</code> 别的，必须先把 <code>$ra</code> 存到栈上</strong>，不然 $ra 被覆盖、<code>jr $ra</code> 回不去（死循环或乱跳）。</li><li>典型开头/结尾：</li></ul><pre class=""><code class="">f:
    addi $sp, $sp, -4     # 栈上开 4 字节
    sw   $ra, 0($sp)      # 存 $ra
    ...
    lw   $ra, 0($sp)      # 取回
    addi $sp, $sp, 4
    jr   $ra
</code></pre>
<ul><li>用了 <code>$s</code> 寄存器也要这样先存后恢复；<code>$t</code> 寄存器调用后不保证还在。</li></ul><h2 id="5-">5. 被问到时的回答套路</h2><ol start="1"><li>先说<strong>这个寄存器代表 C 里哪个变量</strong>（&quot;$t0 是 i，$t1 是数组首地址&quot;）。</li><li>再说<strong>这一段对应 C 哪一行</strong>（&quot;这 4 行就是 <code>x = numbers[i]</code>&quot;）。</li><li>让你预测输出：拿第一个、第二个值手算一遍循环，别跳着猜。</li><li>真不会：说&quot;我觉得这里是在算 &amp;numbers[i]，因为它乘了 4 再加首地址&quot;——讲出推理比答对还重要。</li></ol><h2 id="6--lab02tutor-">6. 顺便复习你自己交过的 lab02（tutor 可能拿它问）</h2><p>grade（if/else 链）、count（while 计数）、seven<em>eleven（循环 + 取余判断）、sequence（循环 + 步长）。
开 lab 前把你自己的 <code>.s</code> 打开，每题能口述&quot;哪个寄存器是哪个变量、哪行是循环条件&quot;就够了。
lab03（print</em>bigger / swap_numbers / unordered）截止 <strong>2026-10-06 12:00</strong>，还没开始。</p></div><p style="text-align:right"><a href="https://rakko.cn/posts/comp1511/w23coc#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/comp1511/w23coc</link><guid isPermaLink="true">https://rakko.cn/posts/comp1511/w23coc</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Wed, 30 Sep 2026 04:54:23 GMT</pubDate></item><item><title><![CDATA[RakkoTasks 隐私说明]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/productivity/rakkotasks-privacy">https://rakko.cn/posts/productivity/rakkotasks-privacy</a></blockquote><div><p>RakkoTasks 读你的收件箱，挑出真正需要你处理的事，写成一句中文待办。你的邮件要交给它读，所以这一页讲清楚三件事：它怎么运行，数据去了哪里，它怎么保护你。</p><ul><li><strong>不需要你的邮箱密码</strong>：Outlook 走微软官方授权，Gmail 用可随时撤销的应用专用密码</li><li><strong>只读收件箱</strong>：不会替你发信，也不会删信</li><li><strong>无统计、无广告</strong>：页面里没有任何追踪或第三方脚本</li><li><strong>源代码公开</strong>：每一行都能在 GitHub 上看到</li></ul><h2 id="">它怎么运行</h2><p><strong>你连接自己的邮箱。</strong> 在设置页添加邮箱，全程不需要输入你的邮箱登录密码。Outlook 类邮箱通过微软官方页面授权，RakkoTasks 拿到的是一份授权凭证，不是你的密码；Gmail 使用 Google 的「应用专用密码」，它和你的 Google 登录密码是两回事，随时可以在 Google 账户里单独撤销。</p><p><strong>每 15 分钟看一次收件箱。</strong> 后台程序通过加密连接读取收件箱里的新邮件，你也可以在待办页手动刷新。它只读取邮件，不会替你发信，也不会删信。</p><p><strong>AI 判断哪些是你要做的事。</strong> 广告、营销和标题党邮件会被过滤掉。真正需要你处理的事，AI 会写成一句中文待办，并标出截止时间和分类（学业、工作、个人、账单、其他）。</p><p><strong>在手机或电脑上处理。</strong> 打开网页就能查看、勾选和编辑待办，也可以把它安装到主屏幕。待办还能同步到 iPhone 的「提醒事项」，或用订阅链接显示在日历里。</p><p><strong>直接问你的邮件。</strong> 用一句话问「下周有哪些截止」，AI 会在你自己的邮件里查找，回答时附上它引用的原邮件。</p><h2 id="">数据去了哪里</h2><p>RakkoTasks 用到的外部服务就是下表这几家，没有别的。</p><table><thead><tr><th> 服务 </th><th> 会收到 </th><th> 不会收到 </th></tr></thead><tbody><tr><td> RakkoTasks 服务器（数据存放处） </td><td> 拉取到的邮件（标题、发件人、正文，附件只记文件名）、生成的待办和提醒，全部存放在服务器上的一个数据库文件里 </td><td> 不使用任何云数据库或第三方存储服务；附件内容不保存 </td></tr><tr><td> DeepSeek（AI 模型服务） </td><td> 判断邮件时：主题、发件人、日期和正文前 8000 字。问答和生成详情时：你的问题、近 90 天邮件的发件人与主题列表，以及 AI 按需查看的邮件正文（每封最多 4000 字） </td><td> 收件人地址、附件、你的邮箱凭证 </td></tr><tr><td> 你的邮箱服务商（微软 Outlook / Gmail） </td><td> 一次授权登录，以及按时读取收件箱的请求 </td><td> RakkoTasks 不会通过它发信或删信 </td></tr><tr><td> Phainon（登录服务） </td><td> 你的登录过程。它由 RakkoTasks 的作者自建，只负责确认「你是你」 </td><td> 你的邮件和待办；RakkoTasks 也不保存你的登录密码 </td></tr><tr><td> Cloudflare（网络转发） </td><td> 你访问网页时，加密流量经它转发到服务器 </td><td> 它只负责转发，不保存你的邮件和待办 </td></tr></tbody></table><p>DeepSeek 如何处理收到的内容，以 DeepSeek 自己的隐私政策为准。</p><h2 id="">它怎么保护你</h2><p>这些措施都写在代码里。</p><ul><li><strong>不需要你的邮箱密码。</strong> 连接 Outlook 走微软官方授权，连接 Gmail 用应用专用密码，你的邮箱登录密码从头到尾都不会交给 RakkoTasks。不想用了，去微软或 Google 账户里撤销授权，RakkoTasks 就立刻读不到你的邮箱。</li><li><strong>每个人一个独立空间。</strong> 邮箱、邮件和待办全部按账户隔离。想访问别人的数据，系统会当作它根本不存在，连「有没有」都不会透露。</li><li><strong>凭证只进不出。</strong> 应用专用密码和授权凭证保存后，永远不会再返回浏览器。网页只能知道「已连接」或「未连接」。</li><li><strong>原邮件在隔离框里打开。</strong> 邮件的网页内容会先清洗掉脚本和危险代码，再放进一个禁止运行脚本的隔离框里显示。</li><li><strong>默认挡住远程图片。</strong> 很多营销邮件用隐藏图片记录你是否打开了邮件。RakkoTasks 默认不加载远程图片，需要看时你自己点一下再显示。</li><li><strong>AI 不会被邮件牵着走。</strong> 有人会在邮件里写指令，想诱骗 AI 做事。邮件内容交给 AI 时会明确标成「待阅读的资料」，不是指令；AI 只能查你自己的邮件，不能上网，也不能执行任何操作。</li><li><strong>AI 的回答也会过滤。</strong> AI 写出的内容在服务器和网页上各过滤一遍：图片一律移除，链接只保留普通网址，不会在你没点任何东西时悄悄发出请求。</li><li><strong>日志里没有你的邮件。</strong> 运行日志只记录数量和编号，比如「本轮处理 12 封」，不写邮件标题、正文或任何凭证。</li><li><strong>随时停用或删除。</strong> 停用邮箱会立刻清除它的凭证，已经生成的待办保留，以后可以重新启用。彻底删除会把这个邮箱的邮件和由它生成的待办一起删掉。</li><li><strong>日历链接可以随时换。</strong> 日历订阅链接可以一键更换，旧链接立刻失效。同步「提醒事项」用的是单独生成的专用密码，服务器只保存它不可还原的指纹。</li><li><strong>全程加密连接。</strong> 网页访问走 HTTPS。连接邮箱服务器时会严格校验对方证书，冒充的服务器连不上。</li></ul><h2 id="">源代码</h2><p>RakkoTasks 的全部代码公开在 GitHub。上面每一条保护措施，都能在代码里找到对应的实现。</p><p>仓库地址：<a href="https://github.com/KurisuRakko/RakkoTasks">https://github.com/KurisuRakko/RakkoTasks</a></p><p>后端用 Python 写，负责收邮件、调用 AI、存储数据；前端是一个可以安装到主屏幕的网页。</p><p>也可以用 Docker 在自己的机器上部署一份，数据就完全留在你手里。登录部分需要接入一个兼容的登录服务，仓库里的部署说明写了步骤。</p><blockquote><p>内容按 2026 年 9 月的代码撰写。如果这页和代码有出入，以代码为准。</p></blockquote></div><p style="text-align:right"><a href="https://rakko.cn/posts/productivity/rakkotasks-privacy#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/productivity/rakkotasks-privacy</link><guid isPermaLink="true">https://rakko.cn/posts/productivity/rakkotasks-privacy</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Thu, 24 Sep 2026 10:52:20 GMT</pubDate></item><item><title><![CDATA[你的密码去哪了？——Priestess 怎样保管密码，为什么连 Rakko 也看不到]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/productivity/passwd">https://rakko.cn/posts/productivity/passwd</a></blockquote><div><blockquote><p>写于 2026 年 9 月。本文面向没有技术背景的读者，文末附有给技术读者的细节，可以跳过。</p></blockquote>
<p>注册 Priestess 的时候，常有人问：「管理员能看到我的密码吗？」</p><p>答案是：<strong>不能。</strong> 不是 Rakko 承诺「不去看」，而是 Priestess 从一开始就没有把你的密码存下来。这篇文章想讲清楚四件事：</p><ol start="1"><li>Priestess 到底存了什么；</li><li>为什么这样存了之后，连 Rakko 也没法知道你的密码；</li><li>谷歌、学习通这些平台是怎么做的，又出过什么事；</li><li>欧盟是怎样用法律要求网站这样做的。</li></ol><hr/><h2 id="">一、保险箱和榨汁机：两种「保管」方式</h2><p>想象你把一样重要的东西交给别人保管，大致有两种办法。</p><p><strong>第一种是保险箱。</strong> 东西锁进去，需要的时候用钥匙打开，原样取出来。这叫「加密」。它的问题是：<strong>谁有钥匙，谁就能看到原件。</strong> 如果网站把你的密码锁进保险箱，那么掌握钥匙的管理员，或者偷到钥匙的小偷，都能把密码拿出来。</p><p><strong>第二种是榨汁机。</strong> 把一个苹果放进去，出来一杯苹果汁。果汁没法再变回苹果；但同一个苹果每次都会榨出同样的果汁。这在技术上叫「哈希」。</p><p>Priestess 对你的密码用的是<strong>榨汁机</strong>。</p><p>为什么可以这样做？因为 Priestess 根本不需要知道你的密码是什么，只需要<strong>判断你这次输入的对不对</strong>。注册时，它把你的密码「榨」成果汁存起来；以后每次登录，它把你这次输入的密码再榨一遍，两杯果汁一样，就说明密码是对的。整个过程不需要保留苹果本身。</p><h3 id="">有些东西确实只能放保险箱</h3><p>榨汁机不是万能的。有些信息系统必须拿到原件才能工作，这时只能锁进保险箱：</p><table><thead><tr><th> 信息 </th><th> 系统需要原件吗 </th><th> 怎么保管 </th></tr></thead><tbody><tr><td> 你的登录密码 </td><td> 不需要，只要能核对 </td><td> 榨汁机（变不回去） </td></tr><tr><td> 登录状态凭证、找回密码邮件里的链接 </td><td> 不需要，只要能核对 </td><td> 榨汁机 </td></tr><tr><td> 两步验证用的密钥 </td><td> <strong>需要</strong>，系统每 30 秒要用它算出新的 6 位验证码 </td><td> 保险箱（加密保存） </td></tr><tr><td> 发短信所用的服务商账号密码 </td><td> <strong>需要</strong>，系统要拿着它去调用短信服务 </td><td> 保险箱（加密保存） </td></tr></tbody></table><p>规律很简单：<strong>只需要核对的，就榨掉；非用原件不可的，才上锁。</strong> 你的登录密码属于第一种。</p><hr/><h2 id="-priestess-">二、你的密码在 Priestess 里经历了什么</h2><p>光用一台普通榨汁机还不够安全。小偷如果偷走了整仓库的果汁，可以自己拿常见的苹果一个个去榨，看哪杯对得上。所以 Priestess 给这台榨汁机加了三道保险。</p><h3 id="">第一道：一味锁在别处的秘方</h3><p>在榨汁之前，Priestess 会先给你的密码加上<strong>一味秘方</strong>。这味秘方不放在存果汁的仓库（数据库）里，而是单独锁在服务器的另一个保险柜中。</p><p>好处是：就算有人把整个数据库偷走，手里没有秘方，他连「拿苹果去试」都无从下手，因为他根本不知道该怎么复现同样的榨法。</p><p>加秘方这一步还有个附带的好处：不管你的密码有多长，都会先变成固定的长度，后面的榨汁机就不会漏掉其中任何一个字。</p><h3 id="">第二道：每个人独一无二的调料</h3><p>每个账号在榨汁时还会额外加一撮<strong>随机调料</strong>，每个人都不一样。</p><p>于是，就算你和另一个人碰巧用了同一个密码，存下来的果汁也完全不同。小偷没法提前做一张「常见密码对照表」一次查出成千上万个账号，只能一个账号一个账号地慢慢试。</p><h3 id="">第三道：一台故意很慢的榨汁机</h3><p>Priestess 用的是一台<strong>故意设计得很慢</strong>的榨汁机。</p><p>在一台普通电脑上实测，它榨一次大约要 0.07 秒。你登录时根本察觉不到这点等待。可对小偷来说就完全不同了：普通的快速算法，一台电脑一秒能算几十万次甚至更多；换成这台慢机器，一秒只能算十几次。想把几十亿个可能的密码挨个试一遍，时间会被拉长几万倍。</p><h3 id="">最后：贴一张写明「第几代」的标签</h3><p>每一杯果汁上都贴着标签，写明是用哪一代榨汁机榨的。将来有了更好的机器，你下次登录、密码核对成功的那一刻，系统会自动用新机器重新榨一杯，把旧的换掉，你不需要做任何事。这个机制现在就在工作：早期没有加「秘方」的旧记录，会在用户下次登录时自动换成新做法。</p><h3 id="">顺带一提：连「这个账号存不存在」也不泄露</h3><p>如果有人输入一个根本不存在的用户名，Priestess 仍然会假装认真榨一遍汁再回答「登录失败」。这样，别人就没法通过「回答快慢」来判断某个用户名是否注册过。</p><hr/><h2 id="-rakko-">三、为什么 Rakko 看不到你的密码</h2><p>把上面的内容串起来，「看不到」体现在四个地方：</p><ol start="1"><li><strong>仓库里没有。</strong> 数据库里只有果汁，没有苹果。Rakko 打开数据库，看到的是一串毫无意义的字符，和小偷看到的一样。</li><li><strong>管理面板上没有。</strong> 管理员查看用户信息时，只能看到「已设置密码：是 / 否」。</li><li><strong>日志里没有。</strong> 系统在运行时会记录一些日志，比如「某时某刻有人登录失败」，但从不记录你输入的密码内容。</li><li><strong>能换锁，不能看钥匙。</strong> 如果你忘了密码，可以通过邮件自助重置；Rakko 也可以直接给账号设一个新密码。管理员这样做之前要再输一次自己的管理员密码，而且会留下操作记录。无论哪种方式，都是用新密码<strong>覆盖</strong>旧密码，旧密码不会被任何人看到。</li></ol><h3 id="">说句实在话</h3><p>「看不到」有一个边界，我们不想夸大。</p><p>你登录时，密码需要通过加密的网络连接交给服务器核对。就像你把钥匙递给门卫验一下，<strong>门卫接过去的那一瞬间是拿得到的</strong>。Priestess 的规矩是：验完立刻忘掉，不抄在本子上、不拍照、不告诉任何人。这份保证来自程序的写法和运营的纪律，而不是物理上不可能。</p><p>真正连这一瞬间都省掉的办法，是 <strong>Passkey（通行密钥）</strong>：用手机或电脑的指纹、面容解锁来登录，密码压根不需要发给服务器，服务器那边只保存一份「只能用来验证、不能用来冒充你」的信息。这也是 Priestess 推荐的主要登录方式，密码更多是作为备用。</p><h3 id="">你自己能做的</h3><ul><li><strong>不要在多个网站用同一个密码。</strong> Priestess 保管得再好，如果你在另一个网站用了同一个密码，而那个网站泄露了，坏人就可能拿它来试你的其它账号。</li><li><strong>密码长一点比花哨更重要。</strong> Priestess 要求至少 12 个字符，不强制你加大小写或符号。一句只有你知道的长句子，往往比短而复杂的密码更好记，也更安全。</li><li><strong>用密码管理器，开启两步验证或 Passkey。</strong></li></ul><hr/><h2 id="">四、别人家是怎么做的</h2><p>大公司通常不会把「用哪台榨汁机、放几味调料」全部公开，法律也没有要求它们公开。下面看两个例子：一个是做得不错、但也犯过错的谷歌；一个是强调密码没有泄露、却被卷进大规模个人信息泄露风波的学习通。</p><h3 id="">谷歌：没公开配方，但公开过自己的失误</h3><p>谷歌没有公开账号密码具体用的是哪一种算法。它在 2019 年的一篇官方博客里讲过总原则：密码先经过单向的「榨汁」处理，然后把榨出来的结果连同用户名一起<strong>再锁进保险箱</strong>（加密），才写进硬盘。等于榨汁机和保险箱两道都用上了。</p><p>有意思的是，这篇博客本身是一份认错声明。谷歌发现，面向企业客户的 G Suite（现在叫 Google Workspace）从 2005 年起有一个漏洞：管理员在后台替员工设置或找回密码时，系统会<strong>多存一份没榨过的原始密码</strong>。2019 年 1 月又出了一次类似问题，一小部分新注册企业客户的密码被原样存放了最多 14 天。谷歌表示，这些数据一直放在自家加密的内部系统里，没有发现被滥用，普通个人账号也不受影响；它通知了受影响企业的管理员，并要求他们重置密码。</p><p>连谷歌都会在「管理员代设密码」这种不起眼的角落出错。所以 Priestess 在这条路径上同样只保存榨过的果汁：管理员替你设新密码时，系统拿到密码就立刻榨掉，不留原件。</p><p>谷歌还有一个给其它开发者用的登录服务 Firebase，这一边的做法倒是公开的：它用的是一种改良版的 <strong>scrypt</strong> 慢速算法。scrypt 不光费时间，还特别费内存，小偷很难靠专门定制的硬件批量加速。每个项目都有自己独立的一套参数和密钥；从别处搬进来的旧密码记录，会在用户第一次成功登录时自动换成新做法，和前面讲的 Priestess「贴标签、自动换代」是同一个思路。</p><p>谷歌也有必须用<strong>保险箱</strong>的场景：<strong>谷歌密码管理器</strong>。它替你记住的是你在其它网站的密码，将来要原样填回去，所以不能榨，只能加密保存。默认情况下，这个保险箱的钥匙由你的谷歌账号保管；如果你手动开启「设备端加密」，钥匙就只存在你自己的设备上，连谷歌也打不开。</p><p>此外，从 2023 年 10 月起，谷歌把 Passkey 设成了个人账号的默认登录选项，希望大家尽量不再用密码。</p><h3 id="2022-">另一种教训：2022 年的学习通</h3><p>2022 年 6 月，有人在网上兜售号称来自「超星学习通」的 1.7 亿多条学生信息，包括姓名、手机号、学校、学号等，话题一度冲上微博热搜第一。</p><p>学习通很快回应：已经报警；技术排查了十几个小时，还没有发现明确的泄露证据。它同时强调自己<strong>不保存明文密码</strong>，采用的是「单向加密」，也就是本文说的榨汁机，连公司内部员工都拿不到密码原文，网传「密码泄露」不属实。</p><p>但媒体随后发现，有社工库机器人（黑产用来倒卖、查询个人信息的工具）已经能查到与本人学习通资料一致的学号、姓名、手机号，不少网友也说自己接到了骚扰或诈骗电话，怀疑与此有关。在我们能查到的公开资料里，还没有看到这件事的最终调查结论。</p><p>这个案子的教训有两层：</p><ul><li><strong>榨汁机只保护密码。</strong> 就算密码榨得好好的，姓名、手机号、学校这些信息一旦流出，照样能被拿去骗人。一个网站要保护的，远不止密码。这也是后面要讲的欧盟法律管的是「所有个人数据」，而不只是密码的原因。</li><li><strong>榨汁机也分好坏。</strong> 当时有专家提醒：「单向加密」如果用的方法不够强，只要有足够的时间和算力，照样可以被解开。所以光说「我们加密了」还不够，还要看用的是哪台榨汁机、有没有秘方和调料。</li></ul><h3 id="">放在一起看</h3><p>做得好的公司，思路其实非常一致：<strong>只存果汁，用慢机器，秘方分开放，并且努力让大家不用密码。</strong> 但就算做到了这些，还有两件事要时刻记着：一是谷歌那样藏在角落里的疏忽，二是学习通风波提醒我们的：密码之外的个人信息同样要守住。</p><hr/><h2 id="">五、欧盟是怎样定这些规矩的</h2><p>在欧洲，网站该怎样保护用户数据，主要由一部法律决定：<strong>《通用数据保护条例》（GDPR）</strong>。它常被当作全球个人信息保护的标杆。</p><h3 id="">欧盟的法律是怎么「写」出来的</h3><p>欧盟立法有点像一份合同的诞生：</p><ul><li><strong>起草人</strong>是欧盟委员会，只有它可以正式提出法律草案。</li><li><strong>签字人</strong>有两位：一位是欧洲议会，由欧洲选民直接选出的议员组成；另一位是欧盟理事会，由各成员国政府的部长组成。两边都同意，法律才能通过。</li><li>两边意见不一时，三方会坐下来反复协商，逐条讨价还价，直到拿出一份双方都能接受的文本。</li></ul><p>欧盟的法律分几种。其中「条例」一旦通过，<strong>所有成员国直接照办</strong>，不需要各国再自己改写成本国法律。GDPR 就是一部条例。它取代的是 1995 年的一份旧「指令」：指令只规定目标，由各国自行立法落实，结果各国宽严不一。</p><p>GDPR 从提出到落地花了六年多：</p><ul><li><strong>2012 年 1 月</strong>，欧盟委员会提出草案；</li><li>之后经过四年多谈判，<strong>2016 年 4 月</strong>正式通过；</li><li>法律给企业留了两年准备期，<strong>2018 年 5 月 25 日</strong>起正式实施。</li></ul><h3 id="">它并没有规定「用哪台榨汁机」</h3><p>你可能以为，这样一部法律会写明「密码必须用某某方法保存」。其实没有。GDPR 的写法是：</p><blockquote><p>企业要考虑<strong>当下的技术水平</strong>、实施成本和数据面临的风险，采取与风险相称的技术和管理措施，例如加密，并且要能持续保证数据的保密性。（第 32 条大意）</p></blockquote>
<p>此外，它还要求个人数据必须以<strong>确保安全</strong>的方式处理（第 5 条），并要求企业<strong>从设计之初、默认状态下</strong>就只处理必要的数据（第 25 条）。</p><p>为什么不直接写死方法？因为一部法律要用很多年，而技术几年就会变。二十年前被认为足够安全的算法，今天已经可以被轻易破解。如果法律写死某种方法，它很快就会过时，甚至会保护那些照着旧标准做、实际已经不安全的企业。</p><p>所以 GDPR 选择只规定「要做到什么程度」，不规定「具体用什么工具」。这就好比交通法规不规定你必须开哪个牌子的车，只要求刹车必须合格；而且「合格」的标准会随着时代自动提高。</p><h3 id="">胡萝卜和大棒</h3><p><strong>胡萝卜</strong>：如果企业发生了数据泄露，原则上要尽快报告监管机构，情况严重时还要逐一通知受影响的用户。但法律也规定：如果泄露出去的数据被处理得<strong>让外人看不懂</strong>，比如经过了加密，就可以不必逐一通知用户（第 34 条）。也就是说，平时防护做得好，出事时的麻烦就小得多。</p><p><strong>大棒</strong>：没做好安全措施，最高可以罚 1000 万欧元，或者全球年营业额的 2%，按两者中较高的算；违反更基本的数据处理原则，上限翻倍，达到 2000 万欧元或 4%（第 83 条）。</p><h3 id="">谁来说明「怎样才算做好」</h3><p>既然法律只写原则，就需要有人把原则翻译成具体做法。这份工作由各国的数据保护机构和它们共同组成的<strong>欧洲数据保护委员会（EDPB）</strong>承担。它们会发布指南，举大量例子。</p><p>其中一个例子几乎就是在讲本文的主题：</p><blockquote><p>一个菜谱网站被黑客入侵，1200 个用户的密码被偷走。但这些密码都用当下可靠的方法「榨」过，还各自加了随机调料，而调料没有一起泄露。EDPB 认为，这种情况对用户权益<strong>没有风险</strong>，网站甚至不必向监管机构报告，只需要内部登记；不过仍然建议网站提醒用户换密码。</p></blockquote>
<p>EDPB 还在同一处指出：更理想的做法是采用<strong>根本不需要服务器处理密码</strong>的登录方式，也就是前面说的 Passkey 这一类。</p><h3 id="">两张真实的罚单</h3><p><strong>德国，Knuddels（2018 年）。</strong> 这是一个德国聊天网站，把用户密码原样存放，没有做任何「榨汁」处理。2018 年它被黑客入侵，约 33 万组账号和密码被公开到网上。当地数据保护机构认定它违反了 GDPR 关于安全措施的规定，开出 2 万欧元罚单，这也是 GDPR 实施后德国的第一张罚单。金额不算高，是因为该公司事后非常配合，也很快完成了整改。</p><p><strong>爱尔兰，Meta（2024 年）。</strong> Meta（Facebook 的母公司）在 2019 年主动向爱尔兰数据保护机构报告：公司发现，部分用户的密码以明文形式存放在内部系统里。这些密码<strong>并没有泄露给外人</strong>，但监管机构依然认定它没有采取适当的安全措施、没有按规定报告和记录，于 2024 年 9 月处以 <strong>9100 万欧元</strong>罚款并给予训诫。</p><p>两个案子放在一起看，道理很清楚：<strong>把密码原样存着，这件事本身就是违规</strong>，不需要等到真的被偷。</p><h3 id="-priestess-">这些规矩和 Priestess 有什么关系</h3><p>先说清楚：GDPR 约束的是在欧盟境内经营、或者面向欧盟境内的人提供服务的机构，就算机构本身不在欧盟也一样。Priestess 是一个个人运营的服务，并不以欧盟用户为对象，严格来说是否适用要看具体情况，本文也不构成法律意见。我们把 GDPR 当作一把<strong>标尺</strong>，用来检验自己做得够不够好。中国的《个人信息保护法》第五十一条同样要求处理个人信息时采取加密、去标识化等安全技术措施，方向是一致的。</p><p>拿这把标尺量一量：</p><table><thead><tr><th> 规矩的要求 </th><th> Priestess 的做法 </th></tr></thead><tbody><tr><td> 采取与风险相称、符合当下技术水平的措施 </td><td> 密码经过「秘方 + 随机调料 + 慢速榨汁机」处理，并留有将来升级的机制 </td></tr><tr><td> 持续保证数据保密 </td><td> 管理面板不显示密码，日志不记录密码 </td></tr><tr><td> 只处理必要的数据 </td><td> 管理员只能看到「有没有设置密码」这一项 </td></tr><tr><td> 泄露的数据应让外人看不懂 </td><td> 数据库即使被整个偷走，也无法从中还原出任何人的密码 </td></tr><tr><td> 更推荐不需要服务器处理密码的方式 </td><td> 主推 Passkey 登录，密码作为备用 </td></tr></tbody></table><hr/><h2 id="">结语</h2><p>保护密码最好的办法，是从一开始就<strong>不保存它</strong>。</p><p>Priestess 不保存你的密码，只保存一杯变不回苹果的果汁；Rakko 看不到你的密码，不是因为自觉不去看，而是没有东西可看。欧盟的法律没有告诉大家该用哪台榨汁机，但它把道理讲得很明白：你替别人保管的东西，要用这个时代最靠谱的办法去保管。</p><hr/><h2 id="">附：给懂技术的朋友</h2><p>看不懂这一节完全没关系，跳过即可。</p><ul><li><strong>密码哈希</strong>：先用服务端密钥（pepper）对密码做 HMAC-SHA-256，结果 base64url 编码后再做 bcrypt（cost 10，16 字节随机盐，盐来自 CSPRNG），最后加上版本前缀 <code>v2.bcrypt-pepper.</code> 存入数据库。pepper 以 Worker secret 注入，不进入数据库和代码仓库。这与 OWASP Password Storage Cheat Sheet 推荐的 bcrypt 加 pepper 的预哈希做法一致。</li><li><strong>HMAC 预处理的副作用</strong>：bcrypt 只取输入的前 72 字节，而 HMAC 输出编码后固定为 43 个字符，所以 Priestess 允许的最长 4096 字符的密码，每一个字符都会参与计算；同时 pepper 让「password shucking」式的攻击无法进行。</li><li><strong>参数升级</strong>：没有版本前缀的旧式纯 bcrypt 记录，在登录校验成功后会自动重算为 v2 格式，并写入审计日志。</li><li><strong>防用户名枚举</strong>：用户名不存在时也会对一个固定的假哈希执行一次 bcrypt 比对，让两种情况的响应耗时接近。</li><li><strong>高熵凭证只做 SHA-256</strong>：会话 token、密码重置 token、OIDC client secret 都是系统随机生成的高熵字符串，不怕字典攻击，存 SHA-256 摘要即可；慢哈希是专门针对人类挑选的低熵密码的。</li><li><strong>必须可逆的秘密</strong>：TOTP 密钥、短信服务商凭证等使用 AES-GCM 加密保存，密钥与数据库分离。</li><li><strong>坦白说</strong>：OWASP 目前把 Argon2id 列为首选，并把 bcrypt 归为遗留系统的选项；cost 10 是它给出的 bcrypt 最低推荐值。版本前缀机制就是为将来平滑迁移准备的。</li></ul><hr/><h2 id="">参考资料</h2><ul><li><a href="https://eur-lex.europa.eu/eli/reg/2016/679/oj/eng">《通用数据保护条例》（Regulation (EU) 2016/679）原文，EUR-Lex</a></li><li><a href="https://www.edps.europa.eu/data-protection/data-protection/legislation/history-general-data-protection-regulation_en">欧洲数据保护监督员（EDPS）：GDPR 的立法历程</a></li><li><a href="https://www.edpb.europa.eu/our-work-tools/documents/public-consultations/2021/guidelines-012021-examples-regarding-data-breach_en">EDPB：Guidelines 01/2021 on Examples regarding Personal Data Breach Notification（案例 06）</a></li><li><a href="https://www.dataprotection.ie/en/news-media/press-releases/DPC-announces-91-million-fine-of-Meta">爱尔兰数据保护委员会：对 Meta 处以 9100 万欧元罚款（2024-09-27）</a></li><li><a href="https://iapp.org/news/a/germanys-first-fine-under-the-gdpr-offers-enforcement-insights">IAPP：德国 GDPR 首张罚单（Knuddels）</a></li><li><a href="https://gdprhub.eu/index.php?title=LfDI_-_O_1018/115">GDPRhub：LfDI Baden-Württemberg – O 1018/115</a></li><li><a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html">OWASP Password Storage Cheat Sheet</a></li><li><a href="https://cloud.google.com/blog/products/g-suite/notifying-administrators-about-unhashed-password-storage">Google Cloud 博客：Notifying administrators about unhashed password storage（2019-05-22）</a></li><li><a href="https://github.com/firebase/scrypt">Firebase：Firebase Authentication 使用的改良版 scrypt</a></li><li><a href="https://blog.google/technology/safety-security/passkeys-default-google-accounts/">Google 博客：Passkeys are now enabled by default for Google users（2023-10）</a></li><li><a href="https://gizmodo.com/google-password-manager-on-device-encryption-how-to-set-1849089244">Gizmodo：谷歌密码管理器的设备端加密</a></li><li><a href="https://www.thepaper.cn/newsDetail_forward_18670697">澎湃新闻：超星学习通回应「用户数据泄露」传闻，已向公安机关报案（2022-06）</a></li><li><a href="https://www.secrss.com/articles/43831">南都·隐私护卫队（转载于安全内参）：学习通回应 1.7 亿数据疑泄露，专家称密码加密仍有安全风险（2022-06-21）</a></li></ul></div><p style="text-align:right"><a href="https://rakko.cn/posts/productivity/passwd#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/productivity/passwd</link><guid isPermaLink="true">https://rakko.cn/posts/productivity/passwd</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Wed, 23 Sep 2026 17:49:02 GMT</pubDate></item><item><title><![CDATA[一条线段为什么不是向量子空间：MATH1231 子空间反例速通]]></title><description><![CDATA[<link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-subspace-cover.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-scalar-stretch.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-parameter-check.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-vs-line.svg"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/mathematics/line-segment-not-vector-subspace-math1231">https://rakko.cn/posts/mathematics/line-segment-not-vector-subspace-math1231</a></blockquote><div><blockquote><p>这篇只解决一个问题：为什么</p><p>$$
S={t\mathbf v:0\le t\le 10}
$$</p><p>这种“从原点出发的一段线段”不是 vector subspace。</p><p>你不用背一整页公理。考试里只要抓住一个失败点：<strong>scalar multiplication 不封闭</strong>。</p></blockquote>
<p><img alt="封面：有限线段被数乘拉出范围" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-subspace-cover.svg"/></p><h2 id="0-">0. 题目在说什么？</h2><p>题目：</p><p>$$
\mathbf v=\begin{pmatrix}1\2\3\end{pmatrix}\in\mathbb R^3.
$$</p><p>Show that the line segment</p><p>$$
S={t\mathbf v:0\le t\le 10}
$$</p><p>is not a vector subspace.</p><p>先翻译成人话：</p><ul><li>$\mathbf v$ 是一个固定方向；</li><li>$t\mathbf v$ 表示沿着这个方向走；</li><li>$0\le t\le 10$ 表示只能从 $0\mathbf v$ 走到 $10\mathbf v$；</li><li>所以 $S$ 不是整条无限长直线，而是一条<strong>有限线段</strong>。</li></ul><p>如果把它想象成数轴上的一段，就是：</p><p>$$
0\mathbf v,\ 1\mathbf v,\ 2\mathbf v,\ \ldots,\ 10\mathbf v
$$</p><p>以及中间所有小数倍的位置。</p><h2 id="1-">1. 子空间最怕什么？</h2><p>如果 $S$ 是 $\mathbb R^3$ 的 vector subspace，它至少必须满足：</p><table><thead><tr><th> 必须满足的条件 </th><th> 意思 </th></tr></thead><tbody><tr><td> zero vector in $S$ </td><td> 零向量要在集合里 </td></tr><tr><td> closed under vector addition </td><td> 两个集合里的向量相加，还要在集合里 </td></tr><tr><td> closed under scalar multiplication </td><td> 集合里的向量乘任何实数，还要在集合里 </td></tr></tbody></table><p>这题里面，零向量其实在：</p><p>$$
0\mathbf v=\begin{pmatrix}0\0\0\end{pmatrix}\in S,
$$</p><p>因为 $0\le 0\le 10$。</p><p>所以不能用“零向量不在”秒杀。</p><p>老师用的是第二种思路：</p><blockquote><p>找一个 $x\in S$，但让某个 scalar multiple $kx\notin S$。</p></blockquote>
<p>这就叫：</p><p>$$
S\text{ is not closed under scalar multiplication.}
$$</p><p><img alt="数乘封闭检查：从集合内拉到集合外" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-scalar-stretch.svg"/></p><h2 id="2-">2. 先别被符号绕晕：集合参数和外部倍数不一样</h2><p>这题最容易混的是同一个希腊字母到处飞。</p><p>我建议你考试时心里分清楚两层：</p><table><thead><tr><th> 符号 </th><th> 作用 </th></tr></thead><tbody><tr><td> $t$ </td><td> 用来描述集合里的点：$t\mathbf v$，其中 $0\le t\le 10$ </td></tr><tr><td> $k$ </td><td> 你拿来做 scalar multiplication 的外部倍数，可以是任何实数 </td></tr></tbody></table><p>也就是说：</p><ol start="1"><li>先找一个集合里的向量 $x=t\mathbf v$。</li><li>再用一个外部 scalar $k$ 去乘它。</li><li>检查 $kx$ 还能不能写成 $s\mathbf v$，并且满足 $0\le s\le 10$。</li></ol><p>如果不能，它就跑出 $S$ 了。</p><h2 id="3-">3. 老师的反例：先选一个在集合里的向量</h2><p>取：</p><p>$$
x=\mathbf v=1\mathbf v.
$$</p><p>因为 $1$ 在 $0$ 和 $10$ 之间：</p><p>$$
0\le 1\le 10,
$$</p><p>所以：</p><p>$$
x=\mathbf v\in S.
$$</p><p>这一步非常重要：你要先证明自己选的东西真的在集合里。</p><h2 id="4--11">4. 现在把它乘以 11</h2><p>如果 $S$ 真的是 vector subspace，那么 $x\in S$ 以后，任何实数倍都应该还在 $S$。</p><p>老师取：</p><p>$$
k=11.
$$</p><p>于是：</p><p>$$
kx=11x=11\mathbf v.
$$</p><p>但 $11\mathbf v$ 要在 $S$ 里，就必须能写成 $t\mathbf v$，并且满足：</p><p>$$
0\le t\le 10.
$$</p><p>这里的系数已经是 $11$：</p><p>$$
11&gt;10.
$$</p><p>所以：</p><p>$$
11\mathbf v\notin S.
$$</p><p><img alt="代入检查：1 在范围内，11 超出范围" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-parameter-check.svg"/></p><h2 id="5-">5. 结论怎么写？</h2><p>我们已经找到：</p><p>$$
x\in S,
$$</p><p>但：</p><p>$$
11x\notin S.
$$</p><p>所以：</p><p>$$
S\text{ is not closed under scalar multiplication.}
$$</p><p>因此：</p><p>$$
S\text{ is not a vector subspace of }\mathbb R^3.
$$</p><p>这题到这里就结束了。</p><h2 id="6--11">6. 为什么能想到乘 11？</h2><p>不是玄学。</p><p>集合 $S$ 只允许：</p><p>$$
0\le t\le 10.
$$</p><p>这句话等价于：</p><blockquote><p>系数最多只能到 $10$。</p></blockquote>
<p>所以你只要把一个在里面的向量放大到系数超过 $10$，它就会掉出去。</p><p>最舒服的选择就是：</p><p>$$
x=1\mathbf v\in S.
$$</p><p>然后乘：</p><p>$$
11.
$$</p><p>得到：</p><p>$$
11x=11\mathbf v\notin S.
$$</p><p>如果你想更快，其实也可以乘 $-1$：</p><p>$$
-x=-\mathbf v,
$$</p><p>因为系数 $-1&lt;0$，也不在 $0\le t\le 10$ 里面。</p><p>但视频里用 $11$，我们就按老师的版本写。</p><h2 id="7-">7. 这题的本质：线段不是整条直线</h2><p>一个真正的一维子空间应该长这样：</p><p>$$
L={t\mathbf v:t\in\mathbb R}.
$$</p><p>这里的 $t$ 可以是任何实数：</p><p>$$
\ldots,\ -2,\ -1,\ 0,\ 1,\ 2,\ 11,\ 100,\ \ldots
$$</p><p>所以整条直线可以被随便放大、缩小、反向。</p><p>但题目里的：</p><p>$$
S={t\mathbf v:0\le t\le 10}
$$</p><p>只是一段有限线段。</p><p>它有两个端点：$0\mathbf v$ 和 $10\mathbf v$。</p><p>一旦你把里面的点继续往外拉，例如 $11\mathbf v$，它就不在这段线段上了。</p><p><img alt="整条直线 vs 有限线段" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/line-segment-vs-line.svg"/></p><h2 id="8-">8. 考试可直接抄的版本</h2><pre class="language-text lang-text"><code class="language-text lang-text">Take x = v = 1v. Since 0 &lt;= 1 &lt;= 10, we have x in S.

However, 11x = 11v. This is not in S, since the coefficient 11 does not satisfy 0 &lt;= 11 &lt;= 10.

Therefore S is not closed under scalar multiplication. Hence S is not a vector subspace of R^3.
</code></pre>
<p>如果要写得更数学一点：</p><p>$$
x=\mathbf v=1\mathbf v\in S
$$</p><p>since $0\le 1\le 10$. But</p><p>$$
11x=11\mathbf v\notin S
$$</p><p>since $11&gt;10$. Hence $S$ is not closed under scalar multiplication, so $S$ is not a vector subspace of $\mathbb R^3$.</p><h2 id="9-">9. 初学者检查清单</h2><p>遇到</p><p>$$
S={t\mathbf v:a\le t\le b}
$$</p><p>这种题，按三步走：</p><ol start="1"><li>看它是不是只给了一个有限区间。</li><li>先取一个在区间里的简单数，例如 $t=1$ 或 $t=0$。</li><li>用一个 scalar 把它乘到区间外，例如超过上界，或者变成负数。</li></ol><p>只要你写出：</p><p>$$
x\in S,\qquad kx\notin S,
$$</p><p>就能证明它不是 subspace。</p><h2 id="10-">10. 自测题</h2><h3 id="-1">自测 1</h3><p>设：</p><p>$$
S={t\mathbf v:-2\le t\le 2}.
$$</p><p>证明 $S$ 不是 vector subspace。</p><p>答案：</p><p>取 $x=\mathbf v=1\mathbf v$。因为 $-2\le 1\le 2$，所以 $x\in S$。</p><p>但：</p><p>$$
3x=3\mathbf v.
$$</p><p>系数 $3$ 不满足 $-2\le 3\le 2$，所以 $3x\notin S$。</p><p>因此 $S$ is not closed under scalar multiplication，不是 vector subspace。</p><h3 id="-2">自测 2</h3><p>设：</p><p>$$
S={t\mathbf v:t\ge 0}.
$$</p><p>证明 $S$ 不是 vector subspace。</p><p>答案：</p><p>取 $x=\mathbf v=1\mathbf v$。因为 $1\ge 0$，所以 $x\in S$。</p><p>但：</p><p>$$
-x=-\mathbf v.
$$</p><p>这对应的系数是 $-1$，不满足 $t\ge 0$，所以 $-x\notin S$。</p><p>因此 $S$ is not closed under scalar multiplication，不是 vector subspace。</p><h2 id="11-">11. 最后一口气版总结</h2><p>这节课的核心只有一句：</p><blockquote><p>有限线段不是 vector subspace，因为 subspace 不能有“只能从 0 到 10”这种边界。</p></blockquote>
<p>本题标准反例：</p><p>$$
x=\mathbf v=1\mathbf v\in S,
$$</p><p>但：</p><p>$$
11x=11\mathbf v\notin S.
$$</p><p>所以 $S$ is not closed under scalar multiplication。</p><p>一旦 scalar multiplication 不封闭，它就不是 vector subspace。</p></div><p style="text-align:right"><a href="https://rakko.cn/posts/mathematics/line-segment-not-vector-subspace-math1231#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/mathematics/line-segment-not-vector-subspace-math1231</link><guid isPermaLink="true">https://rakko.cn/posts/mathematics/line-segment-not-vector-subspace-math1231</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Mon, 08 Jun 2026 11:23:17 GMT</pubDate></item><item><title><![CDATA[一眼判断集合不是向量空间：MATH1231 反例速通]]></title><description><![CDATA[<link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-cover.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-flow.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-example-1.svg"/><link rel="preload" as="image" href="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-example-2.svg"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/mathematics/sets-that-are-not-vector-spaces-math1231">https://rakko.cn/posts/mathematics/sets-that-are-not-vector-spaces-math1231</a></blockquote><div><blockquote><p>这篇只解决一个问题：题目给你一个集合 $S$，怎么快速证明它 <strong>不是</strong> vector space。</p><p>重点不是把十条公理背一遍，而是学会找一个反例。一个反例就够了。</p></blockquote>
<p><img alt="封面：closure 被反例打破" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-cover.svg"/></p><h2 id="0-">0. 先把结论说人话</h2><p>Vector space 最重要的感觉是：</p><blockquote><p>你在集合里做正常向量操作，结果还应该留在集合里。</p></blockquote>
<p>这里的“正常向量操作”主要是两件事：</p><ol start="1"><li>scalar multiplication：把向量乘一个数，例如 $2v$、<code>-v</code>、<code>0v</code>。</li><li>vector addition：两个向量相加，例如 $u+v$。</li></ol><p>所以要证明一个集合 <strong>不是</strong> vector space，最爽的方法就是找一个操作让它“跑出去”：</p><table><thead><tr><th> 想破坏什么 </th><th> 你要找什么 </th><th> 写法 </th></tr></thead><tbody><tr><td> 零向量条件 </td><td> $\mathbf{0}\notin S$ </td><td> zero vector is not in $S$ </td></tr><tr><td> 数乘封闭 </td><td> $v\in S$，但 $kv\notin S$ </td><td> not closed under scalar multiplication </td></tr><tr><td> 加法封闭 </td><td> $u,v\in S$，但 $u+v\notin S$ </td><td> not closed under vector addition </td></tr></tbody></table><p><img alt="三步判断流程图" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-flow.svg"/></p><p>记住这句话：</p><blockquote><p>证明“是”要检查很多东西；证明“不是”只要抓到一个失败点。</p></blockquote>
<h2 id="1--vin-s">1. 什么叫 $v\in S$？</h2><p>很多人卡在符号，其实非常机械。</p><p>如果题目写：</p><p>$$
S={x\in\mathbb{R}^3: 2x<em>1+3x</em>2^3-4x_3^2=0},
$$</p><p>那 $v\in S$ 的意思就是：</p><blockquote><p>把 $v$ 的三个坐标代进 $2x<em>1+3x</em>2^3-4x_3^2$，结果等于 $0$。</p></blockquote>
<p>如果结果不是 $0$，那就是 $v\notin S$。</p><p>所以这种题不用想得太玄。它就是“代入检查”。</p><h2 id="2--1">2. 例题 1：用数乘把它踢出去</h2><p>题目：</p><p>$$
S={x\in\mathbb{R}^3: 2x<em>1+3x</em>2^3-4x_3^2=0}.
$$</p><p>Show that $S$ is not a vector space.</p><h3 id="-s-">第一步：找一个在 $S$ 里的向量</h3><p>老师取：</p><p>$$
v=\begin{pmatrix}2\0\1\end{pmatrix}.
$$</p><p>我们先验证它真的在 $S$ 里。把 $x<em>1=2,\ x</em>2=0,\ x_3=1$ 代进去：</p><p>$$
2(2)+3(0)^3-4(1)^2
=4+0-4
=0.
$$</p><p>所以：</p><p>$$
v\in S.
$$</p><h3 id="-2">第二步：把它乘以 2</h3><p>$$
2v=2\begin{pmatrix}2\0\1\end{pmatrix}
=\begin{pmatrix}4\0\2\end{pmatrix}.
$$</p><p>现在检查 $2v$ 还在不在 $S$：</p><p>$$
2(4)+3(0)^3-4(2)^2
=8+0-16
=-8.
$$</p><p>这不是 $0$，所以：</p><p>$$
2v\notin S.
$$</p><p><img alt="例题 1：v 在 S 中，但 2v 不在 S 中" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-example-1.svg"/></p><h3 id="">结论怎么写？</h3><p>因为 $v\in S$，但 $2v\notin S$，所以 $S$ is not closed under scalar multiplication。</p><p>于是：</p><p>$$
S\text{ is not a vector space.}
$$</p><h3 id="-201">为什么老师会想到 $(2,0,1)$？</h3><p>不是玄学，是在凑数。</p><p>原条件是：</p><p>$$
2x<em>1+3x</em>2^3-4x_3^2=0.
$$</p><p>想找一个简单向量，就先让中间那项消失：</p><p>$$
x_2=0.
$$</p><p>再取一个简单的：</p><p>$$
x_3=1.
$$</p><p>条件就变成：</p><p>$$
2x_1-4=0.
$$</p><p>所以：</p><p>$$
x_1=2.
$$</p><p>于是自然得到：</p><p>$$
(2,0,1).
$$</p><p>这就是找反例的常见套路：把变量设成 $0$ 或 $1$，让式子尽量简单。</p><h2 id="3--2">3. 例题 2：用加法把它踢出去</h2><p>题目：</p><p>$$
S=\left{\begin{pmatrix}a\b\c\end{pmatrix}\in\mathbb{R}^3:(a-b)c=0\right}.
$$</p><p>Find two non-zero elements of $S$ and show $S$ is not closed under vector addition.</p><h3 id="">先看条件到底在说什么</h3><p>$$
(a-b)c=0
$$</p><p>两个东西相乘等于 $0$，所以至少有一个是 $0$：</p><p>$$
a-b=0
$$</p><p>或者：</p><p>$$
c=0.
$$</p><p>也就是：</p><p>$$
a=b
$$</p><p>或者：</p><p>$$
c=0.
$$</p><p>所以 $S$ 不是一个单纯的平面，而像是两块条件拼在一起：</p><ul><li>一块是所有满足 $a=b$ 的向量；</li><li>另一块是所有满足 $c=0$ 的向量。</li></ul><h3 id="">第一步：从两块里各拿一个向量</h3><p>取：</p><p>$$
u=\begin{pmatrix}1\1\1\end{pmatrix},
\qquad
w=\begin{pmatrix}1\2\0\end{pmatrix}.
$$</p><p>验证 $u\in S$：</p><p>$$
(1-1)(1)=0.
$$</p><p>验证 $w\in S$：</p><p>$$
(1-2)(0)=0.
$$</p><p>所以 $u,w\in S$。</p><h3 id="">第二步：把它们相加</h3><p>$$
u+w
=\begin{pmatrix}1\1\1\end{pmatrix}
+\begin{pmatrix}1\2\0\end{pmatrix}
=\begin{pmatrix}2\3\1\end{pmatrix}.
$$</p><p>现在检查这个和还在不在 $S$：</p><p>$$
(2-3)(1)=-1.
$$</p><p>不是 $0$，所以：</p><p>$$
u+w\notin S.
$$</p><p><img alt="例题 2：两块条件各取一个，和掉出 S" src="https://gist.githubusercontent.com/KurisuRakko/2f70f3b848671ed61aa3a50e8b29f479/raw/vector-space-example-2.svg"/></p><h3 id="">结论怎么写？</h3><p>因为 $u,w\in S$，但 $u+w\notin S$，所以 $S$ is not closed under vector addition。</p><p>于是：</p><p>$$
S\text{ is not a vector space.}
$$</p><h2 id="4--vector-space">4. 一眼识别：什么时候优先怀疑它不是 vector space？</h2><p>看到下面这些东西，要立刻警觉：</p><table><thead><tr><th> 条件里出现 </th><th> 为什么危险 </th></tr></thead><tbody><tr><td> 平方、立方，例如 $x<em>3^2$、$x</em>2^3$ </td><td> 数乘后指数会变，例如 $(2x)^2=4x^2$，比例乱掉 </td></tr><tr><td> 两个变量相乘，例如 $xy$、$(a-b)c$ </td><td> 加法通常会破坏乘积为零的结构 </td></tr><tr><td> 常数项，例如 $x+y=1$ </td><td> 零向量通常不满足 </td></tr><tr><td> 绝对值、不等式、圆、球面 </td><td> 一般不容易对加法/数乘封闭 </td></tr></tbody></table><p>但注意：这只是“怀疑”。考试证明还是要写出具体反例。</p><h2 id="5-">5. 考试可直接抄的模板</h2><h3 id="-a">模板 A：数乘不封闭</h3><pre class="language-text lang-text"><code class="language-text lang-text">Take v = (...) in S, since ...

However, kv = (...), and substituting this into the defining condition gives ...
Thus kv is not in S.

Hence S is not closed under scalar multiplication, so S is not a vector space.
</code></pre>
<h3 id="-b">模板 B：加法不封闭</h3><pre class="language-text lang-text"><code class="language-text lang-text">Take u = (...) and v = (...) in S, since ...

However, u + v = (...), and substituting this into the defining condition gives ...
Thus u + v is not in S.

Hence S is not closed under vector addition, so S is not a vector space.
</code></pre>
<h3 id="-c">模板 C：零向量不在集合里</h3><pre class="language-text lang-text"><code class="language-text lang-text">The zero vector is not in S, since substituting 0 into the defining condition gives ...

Therefore S is not a vector space.
</code></pre>
<h2 id="6-">6. 怎么自己找反例？</h2><p>按这个顺序试：</p><ol start="1"><li>先代零向量。零向量不在，直接结束。</li><li>如果有平方/立方，试找一个 $v\in S$，再试 $2v$。</li><li>如果有乘积等于 $0$，试从两个分支各拿一个向量，再相加。</li><li>如果题目条件很复杂，就先把一些变量设成 $0$ 或 $1$，让式子变简单。</li></ol><p>这就是这节课真正想训练的东西：不是背答案，而是会制造一个会跑出集合的向量。</p><h2 id="7-">7. 自测题</h2><h3 id="-1">自测 1</h3><p>$$
S={(x,y)\in\mathbb{R}^2:x^2+y=0}.
$$</p><p>证明 $S$ 不是 vector space。</p><p>答案：</p><p>取：</p><p>$$
v=(1,-1).
$$</p><p>因为：</p><p>$$
1^2+(-1)=0,
$$</p><p>所以 $v\in S$。</p><p>但：</p><p>$$
2v=(2,-2),
$$</p><p>而：</p><p>$$
2^2+(-2)=2\ne0.
$$</p><p>所以 $2v\notin S$。因此 $S$ is not closed under scalar multiplication，不是 vector space。</p><h3 id="-2">自测 2</h3><p>$$
S={(x,y,z)\in\mathbb{R}^3:xy=0}.
$$</p><p>证明 $S$ 不是 vector space。</p><p>答案：</p><p>取：</p><p>$$
u=(1,0,0),\qquad v=(0,1,0).
$$</p><p>因为两个向量都满足 $xy=0$，所以 $u,v\in S$。</p><p>但：</p><p>$$
u+v=(1,1,0),
$$</p><p>此时：</p><p>$$
xy=1\ne0.
$$</p><p>所以 $u+v\notin S$。因此 $S$ is not closed under vector addition，不是 vector space。</p><h2 id="8-">8. 最后一口气版总结</h2><p>证明集合不是 vector space，不要硬查全部公理。</p><p>你只需要找一个失败点：</p><ul><li>$\mathbf{0}\notin S$；</li><li>或者 $v\in S$ 但 $kv\notin S$；</li><li>或者 $u,v\in S$ 但 $u+v\notin S$。</li></ul><p>例题 1 用的是数乘不封闭：$(2,0,1)\in S$，但 $2(2,0,1)\notin S$。</p><p>例题 2 用的是加法不封闭：$(1,1,1),(1,2,0)\in S$，但它们的和 $(2,3,1)\notin S$。</p><p>一句话：</p><blockquote><p>找到一个会跑出去的向量，题就结束了。</p></blockquote></div><p style="text-align:right"><a href="https://rakko.cn/posts/mathematics/sets-that-are-not-vector-spaces-math1231#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/mathematics/sets-that-are-not-vector-spaces-math1231</link><guid isPermaLink="true">https://rakko.cn/posts/mathematics/sets-that-are-not-vector-spaces-math1231</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Sun, 07 Jun 2026 07:07:15 GMT</pubDate></item><item><title><![CDATA[微积分定理秒杀关键词速记]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/mathematics/calculus-theorem-speedrun">https://rakko.cn/posts/mathematics/calculus-theorem-speedrun</a></blockquote><div><p><strong>这是最新文档</strong></p><h2 id="intermediate-value-theorem----ivt">Intermediate Value Theorem (介值定理 - IVT)</h2><p>秒杀关键词： continuous (连续), opposite signs (一正一负), root (根), exists c such that f(c) = 0 (存在c使得函数值等于某数)。</p><p>大白话： 从A点走到B点，如果一个在水面上，一个在水面下，那你肯定得穿过水面。你刚才做对的那道平面题就是这个。</p><h2 id="mean-value-theorem----mvt">Mean Value Theorem (中值定理 - MVT)</h2><p>秒杀关键词： derivative (导数), $f&#x27;(c)$, rate of change (变化率), tangent parallel to secant (切线平行于割线)。</p><p>大白话： 你开车从悉尼去堪培拉，平均时速是 $100$。那路上肯定有那么一瞬间，你的仪表盘速度刚好指在 $100$ 上。只要题目扯到导数和平均变化的关系，闭眼选它。</p><h2 id="maximum-minimum-theorem---">Maximum-Minimum Theorem (极值定理 / 最值定理)</h2><p>秒杀关键词： closed interval (闭区间 $[a,b]$), maximum / minimum (最大值/最小值), bounded (有界的)。</p><p>大白话： 一段连绵不断的山脉，只要圈定一个明确的起点和终点，里面绝对能找出一个最高峰和一个最低谷。</p><h2 id="second-fundamental-theorem-of-calculus-">Second Fundamental Theorem of Calculus (微积分基本定理第二部分)</h2><p>秒杀关键词： 题目里同时出现了积分号 $\int$ 和 求导符号 $\frac{d}{dx}$。</p><p>大白话： 积分的上限是个变量 $x$，然后让你对整个积分式子求导。这就是微积分的核心——求导和积分是逆运算。</p><h2 id="inverse-function-theorem-">Inverse Function Theorem (反函数定理)</h2><p>秒杀关键词： $f^{-1}$, one-to-one (一一映射), inverse (反函数)。</p><p>大白话： 专门用来算反函数的导数的。原函数某点的斜率如果是 $2$，反函数对应点的斜率就是 $\frac{1}{2}$。</p><h2 id="fundamental-theorem-of-algebra-">Fundamental Theorem of Algebra (代数基本定理)</h2><p>秒杀关键词： polynomial (多项式), complex roots (复数根)。</p><p>大白话： $n$ 次多项式必定有 $n$ 个复数根。这在你们这门微积分课里多半是个凑数的干扰项。</p><h2 id="split-function-theorem-">Split Function Theorem (分段函数定理)</h2><p>秒杀关键词： piecewise function (分段函数)，检查连接点 (break point)。</p><p>大白话： 就是左极限等于右极限，左导数等于右导数那套东西。</p></div><p style="text-align:right"><a href="https://rakko.cn/posts/mathematics/calculus-theorem-speedrun#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/mathematics/calculus-theorem-speedrun</link><guid isPermaLink="true">https://rakko.cn/posts/mathematics/calculus-theorem-speedrun</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Mon, 04 May 2026 23:00:00 GMT</pubDate></item><item><title><![CDATA[逻辑题真值表速通：Part a / Part b 一分钟搞定]]></title><description><![CDATA[<link rel="preload" as="image" href="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic1.png"/><link rel="preload" as="image" href="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic2.png"/><link rel="preload" as="image" href="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic3.png"/><div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://rakko.cn/posts/productivity/truth-table-speedrun">https://rakko.cn/posts/productivity/truth-table-speedrun</a></blockquote><div><h2 id="">第一步：死记四个符号的“作弊规则”</h2><p><img alt="图一：第一组真值表题目截图" src="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic1.png"/></p><p>不要管它们叫什么“合取”、“析取”，你只需要记住它们像什么人：</p><ul><li>∼ <strong>（波浪号）= 杠精。</strong> 专门唱反调。看到 T 就写 F，看到 F 就写 T。</li><li>∧ <strong>（尖尖朝上）= 挑剔狂。</strong> 必须左右两个都是 T，结果才是 T。只要看到哪怕一个 F，结果直接写 F。</li><li>∨ <strong>（圆圆朝下）= 老好人。</strong> 只要左右看到哪怕一个 T，结果就是 T。只有两个都是 F 时，他才勉强写 F。</li><li>→ <strong>（箭头）= 渣男背叛。</strong> 这是唯一需要注意顺序的！<strong>只有</strong>前面是 T，后面是 F （即 T→F）时，结果才是 F（承诺了却做不到，渣男）。其他所有情况（哪怕是 F→F），结果全写 T。</li></ul><h2 id="-part-a">第二步：光速填表 (Part a)</h2><p><img alt="图二：第二组真值表题目截图" src="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic2.png"/></p><p>用上面这四个规则，你可以直接无脑填表了。我拿<strong>图一</strong>给你举个例子，考场上你就按这个步骤在草稿纸上比划：</p><ol start="1"><li><p><strong>看第一列</strong> ∼p∨q</p><ul><li>先看 p，在心里把它“杠”一下（T, T, F, F 变成 F, F, T, T）。</li><li>然后把这串新结果和 q 放在一起，用“老好人” ∨ 规则。</li><li>第一行：F∨T=T</li><li>第二行：F∨F=F</li><li>第三行：T∨T=T</li><li>第四行：T∨F=T</li><li><strong>填表答案就是：T, F, T, T</strong></li></ul></li><li><p><strong>看第二列</strong> p→∼q</p><ul><li>把 q 在心里“杠”一下（变成 F, T, F, T）。</li><li>把 p 放在前面，新 q 放在后面，找“渣男”情况（前 T 后 F）。</li><li>第一行：T→F （抓到渣男了！） =F</li><li>第二行：T→T=T</li><li>第三行：F→F=T</li><li>第四行：F→T=T</li><li><strong>填表答案就是：F, T, T, T</strong></li></ul></li></ol><p><em>(图二和图三完全是一模一样的机械动作，按规则套就完事了。)</em></p><h2 id="-part-b">第三步：秒杀 Part b（终极作弊技巧）</h2><p><img alt="图三：第三组真值表题目截图" src="https://github.com/KurisuRakko/picx-images-hosting/raw/master/yohaku/posts/truth-table-speedrun/pic3.png"/></p><p>这里有个天大的捷径，你发现了吗？<strong>Part b 下面的那串又长又恶心的公式，括号里的内容，其实就是你在 Part a 刚刚填完的那两列！</strong></p><p>你根本不需要从头算，直接把你表里的答案代进去！</p><p>你要选的三个英文单词的意思：</p><ul><li><strong>Tautology</strong> (永真式)：最后算出来四个全是 T。</li><li><strong>Contradiction</strong> (矛盾式)：最后算出来四个全是 F。</li><li><strong>Contingency</strong> (偶然式)：有 T 有 F。</li></ul><p><strong>实战演示：</strong></p><p><strong>图一的 (b)：</strong> ∼(p→∼q)→∼(∼p∨q)</p><ul><li>前半部分 (p→∼q) 就是你的第二列答案（F, T, T, T）。</li><li>后半部分 (∼p∨q) 就是你的第一列答案（T, F, T, T）。</li><li>公式翻译过来就是：∼(第二列)→∼(第一列)。</li><li>我们只测第一行：第二列是 F，第一列是 T。代进去：∼F→∼T，也就是 T→F。触发渣男规则，结果是 <strong>F</strong>。</li><li>我们再测第二行：第二列是 T，第一列是 F。代进去：∼T→∼F，也就是 F→T。不是渣男，结果是 <strong>T</strong>。</li><li><strong>出结果了！</strong> 有 F 有 T，不用再往下算了，直接选 <strong>Contingency</strong>。</li></ul><p><strong>图二的 (b)：</strong> ∼(∼p→q)∧(p∧∼q)</p><ul><li>翻译：∼(第二列)∧(第一列)。</li><li>你自己算一下第一列的结果是：F, T, F, F。第二列的结果是：T, T, T, F。</li><li>用挑剔狂 ∧ 规则代入测试。你会发现每一行算出来都是 F。</li><li>四个全 F，直接选 <strong>Contradiction</strong>。</li></ul><p><strong>图三的 (b)：</strong> (∼p∨∼q)∨∼(p∧q)</p><ul><li>翻译：(第二列)∨∼(第一列)。</li><li>第一列结果：T, F, F, F。第二列结果：F, T, T, T。</li><li>第一行代入：F∨∼T，即 F∨F=F。</li><li>第二行代入：T∨∼F，即 T∨T=T。</li><li>有 F 有 T，选 <strong>Contingency</strong>。</li></ul><p>就这么简单。把那四个小符号的性格记住，拿笔在纸上标一下，这几道题一分钟就能填完。</p></div><p style="text-align:right"><a href="https://rakko.cn/posts/productivity/truth-table-speedrun#comments">览毕，何不一言？</a></p></div>]]></description><link>https://rakko.cn/posts/productivity/truth-table-speedrun</link><guid isPermaLink="true">https://rakko.cn/posts/productivity/truth-table-speedrun</guid><dc:creator><![CDATA[KurisuRakko]]></dc:creator><pubDate>Sat, 18 Apr 2026 14:01:00 GMT</pubDate></item></channel></rss>