Kotlin 11:委托之后为何漏记写入
给任务存取接口套一层“审计包装”,直接调用包装器的 put 会留下日志;改为调用包装器的 putIfAbsent,数据存进去了,日志却没增加。两次写入都是通过同一个 AuditedTaskStore 变量发起的,差异在于后者的实现代码究竟运行在哪个接收对象上。类委托能省转发代码,不会自动改写被委托对象内部的 this。 沿用 10 的任务值对象与别名风险,本篇只做一个可替换的内存文本存取点。虽然接口叫 TaskStore,目前没有关联真实数据库,也没有把 09 的 Task 或 10 的可变标签对象保存进去;原有 submit CLI 仍只打印输入提示,不经过此接口。版本为 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14。 为什么先定义接口,而不先堆一套容器 这里的替换点是保存任务文本、按合成 ID 查询;内存实现足够让调用者和接口分离: 12345678910interface TaskStore { fun put(id: String, text: String) fun find(id: String): ...
Kotlin 10:copy 为何没复制任务标签
把任务记录 original.copy() 交给另一个调用方,按直觉似乎给了它一份独立记录。可如果标签是可变列表,对方删掉一项,原记录的标签也会消失。copy 新建了外层 data class 实例,却没有递归复制它指向的对象。这既是查询快照的边界,也会让“对象还能当哈希键吗”变成实际故障。 本篇在 09 的 Task 初始化实验之外新增 TaskRecord,专门观察生成成员。Task 与 TaskRecord 目前都没有接入旧 submit CLI;记录是值对象原型,不是已持久化任务,更没有建模 12 才会定义的状态转移。实验版本仍为 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14。 哪些属性参加比较与复制 本章的类型只有两个主构造属性和一个类体属性: 123data class TaskRecord(val id: String, val labels: MutableList<String>) { var reviewed: Boolean = false} Kotlin data clas...
Kotlin 09:任务类何时真正初始化完
把任务文本传进构造函数,就能立刻把对象交给其他代码使用吗?还要看属性初始值、init、自定义访问器和懒加载分别在什么时候执行。尤其危险的是在父类构造期间调用可被子类覆盖的方法:此时方法已经可能分派到子类,子类的字段却还没初始化。本篇用一个最小 Task 记录创建路径,再用隔离在测试中的派生类证明这个反例。 沿用 08 的任务输入与标签变换,09 才首次出现真正的 Task 类。它仍只是内存对象的初始化实验:之前的 submit CLI 没有创建这个类,Task 也不执行、排队或持久化。工具链仍是 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14。 构造参数、属性和 init 不在同一个时间点 Task 接受原始文本与一个仅供实验记录顺序的列表。核心声明如下: 12345678910111213141516171819202122class Task(rawText: String, private val events: MutableList<String>) { val text: String = nor...
Kotlin 08:取第一条标签为何遍历了全部
同一份任务标签 "Queued"、"Urgent"、"Quiet"、"Later",先转小写、再筛选 q 开头、最后 take(1)。既然第一项 "Queued" 已经符合条件,后面三项还会不会参与计算?直接对 List 链式调用与先转成 Sequence,得到的结果一样,却有不同的调用轨迹。这不是一次计时竞赛,而是要确定操作在什么时候执行。 本篇承接 07 的同步标签函数,继续在同一个 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14 的累计工程里做实验。查询规则仍未接入 CLI,也没有后台任务;所有结论都以本章的四项输入和具体 List/List.asSequence() 构造方式为边界。 直接对 List 调用时,take(1) 已经太晚 急切版本把回调安在转换和筛选位置,用于记录执行顺序: 12345678fun eagerTaskLabels(labels: List<String>, record: (String)...
Kotlin 07:标签规则里的闭包与返回
有两条任务标签 "Queued"、"Urgent",先统一为小写,再筛选指定前缀。如果前缀在筛选规则创建后、真正调用前发生变化,筛选依据是旧值还是新值?把规则写成 lambda 后,答案由捕获了什么以及何时调用决定,不取决于 lambda 看起来是否“像一段配置”。 沿用 06 的标签查询,本篇只让转换和过滤规则变成可传入的函数;仍是同一进程中的同步集合变换,没有线程池、后台队列或协程。源码位于 examples/kotlin-language/src/main/kotlin/example/tasks/TaskLabelRules.kt,环境继续固定为 Kotlin/JVM 2.2.21、JDK 21 和 Gradle Wrapper 8.14。 函数类型写清了谁负责转换、谁负责决定保留 这里不需要为两条规则先建抽象工厂。传入两个函数就够了: 12345fun selectTaskLabels( labels: List<String>, normalize: (String) -> String, ...
Kotlin 06:只读 List 为何仍会变化
查询任务标签时,把 MutableList<String> 的返回类型改成 List<String>,调用方就不能写 labels.add("running") 了。可这份查询结果会不会在下一次任务更新后自己“变长”?会,只要返回的仍是原列表。接口限制的是这个引用提供哪些操作,不是把它指向的对象冻结。这个区别会影响查询结果、缓存和外部 API 的契约。 在 05 的可选备注输入之外,本篇给同一个合成任务增加查询标签的最小实验。还没有任务存储层或实际并发请求;列表、集合和映射的修改都发生在可控测试里。使用 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14,完整命令与输出在本篇 06 证据目录。 List 没有修改方法,不等于背后的列表不会变化 两段查询函数只差一个复制动作: 123fun taskLabelsView(backing: MutableList<String>): List<String> = backingfun taskLabelsSnapshot(bac...
Kotlin 05:可空字段何时表示缺失
一次任务请求没有填备注,与传了 "note": null,服务端该不该按同一种操作处理?如果还允许 "note": "",仅凭 String? 已经不够区分三种输入。空安全解决“拿到的引用可否为 null”,却不会替业务决定“字段缺席”意味着保留原值、清空备注,还是拒绝请求。 本篇沿用 04 的合成任务输入,用一个可控 Map<String, String?> 模拟外部字段,不声称已经有 JSON 解析或 HTTP 接口。Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14 的行为与编译诊断分别留在累计工程的 05 证据目录。 可空类型只能回答“值可能是 null 吗” String 的非空声明会拒绝 null;String? 则要求调用处考虑空值。Kotlin 空安全文档给出这条静态类型边界。独立的 verification/05-nonnull-rejection.kt 写了 val invalidNote: String = null,在冻结版本下 compileK...
Go 24:HTTP 客户端期限与连接资源怎样配合
上篇区分了提交请求、后台任务和 HTTP 服务器三个所有者。如果任务在统计前还需访问另一个 HTTP 服务,第四个时间边界就出现了:连接何时建好,服务器何时开始应答,响应体何时读完,以及任务被取消时这次下游请求由谁停止。本章在同一个累计任务服务的分析路径上接入可选的合成下游;完整代码与实验包、SHA-256及独立解包指令保留本次正反证据。 建连预算不能代替整个请求期限 固定 Go 1.27.1 的 net.Dialer.Timeout 文档说它控制一次连接建立最多等待多久;DNS 得到多个地址时,这个预算还可能被分配到不同候选。它不能限制已连上以后服务器要多久才发响应。http.Client.Timeout 的范围更大:包括连接、重定向和读取响应体;Client.Do 已返回响应头后,读取 Body 时这个计时器仍然有效。任务自己的 context 是另一条取消通路,来自服务而非提交 HTTP 请求的 context。三者不是“都设 30ms 所以完全一样”的参数别名。 任务分析器可选地先执行 probeDownstream(taskContext, client, baseUR...
Kotlin 04:字符串长度与 UTF-8 字节不能互换
给任务文本设定“最多 12 个字符”,然后拿 text.length 判断,"🙂" 会被算成 2。若把同一限制用在网络字节数上,又会把它算成 4。两个数字都正确,问题在于“字符”没有说明计量单位。04 先把合成任务输入的长度问题拆开:UTF-16 代码单元、Unicode 码点、UTF-8 字节,各有不同的用途;至于用户眼里有几个字,这三种计数均不承诺回答。 沿用 03 的任务预览,本篇只增加一个文本计量函数和一个任务标识的正则实验。计量与标识校验尚未接入 CLI;命令行接受 submit 检索🙂,不代表这条输入经过字节长度规则、已入队或已持久化。实验环境为 Kotlin/JVM 2.2.21、JDK 21、Gradle Wrapper 8.14。 下标指向的是 Char,不是完整的码点 Kotlin 的字符串文档允许用 text[index] 取 Char。在本篇的 JVM 平台上,JDK 21 的 String.length() 以 UTF-16 代码单元计数;索引取到的是一个 16 位 Char。中文 "中" 位于基本多文种平面...
Kotlin 03:函数参数和返回值怎样约束任务输入
taskProposal("alpha") 没有传重试次数,究竟用了什么值?如果改成 taskProposal(" ", retries = 6),调用方得到 null,还是抛出异常?参数列表和返回类型把这些问题分开了:省略实参有缺省规则,空白内容可以没有预览结果,非法的重试配置则必须被拒绝。 沿用 02 的命令解析器,本篇给同一个合成任务系统增加一个尚未接入 CLI 的输入预览函数。它只返回格式化文本,没有任务实体、队列、执行器或持久化;函数名中的 proposal 也不表示已经提交。实验环境仍是 Kotlin 2.2.21、Gradle 8.14、JDK 21。 省略参数与显式覆盖是不同的调用 核心函数的公开契约很短: 1234567fun taskProposal(text: String, retries: Int = 2, vararg labels: String): String? { if (retries !in 0..5) rejectRetries(retries) require(labels...










