我用逻辑或给配置项设默认值,用户明明传了一个合法的 0,却被我当成没传替换成了默认值,因为 || 判断的是假值不是是否缺失,而 0、空字符串、false 都是合法却为假的值的深度复盘

我有个配置项 pageSize,为了用户没配时给默认值 20,写得很顺手:const pageSize = config.pageSize || 20。一直好好的,直到有用户反馈:我把 pageSize 配成了 0(业务里 0 表示不分页、返回全部),系统却还是按 20 分页、我的 0 不生效!一看代码就傻眼:config.pageSize 明明是 0,可 0 || 20 的结果是 20——|| 把用户合法配置的 0 当成了没配。复盘才想明白:a || b 的语义是当 a 是假值(falsy)时取 b,而假值不只有 null/undefined,0、空字符串、false、NaN 这些合法存在的值也都是假值;我真正想表达的是没提供(null/undefined)时才用默认,但 || 把提供了但值是 0/空/false 也当成该用默认,混淆了不存在和存在但值为空/零/假。正解是用空值合并运算符 ??,只在 null/undefined 时取默认、保留 0/空/false。这篇复盘从故障现场讲到 falsy、|| 与 ?? 的区别,再到设默认值用 ??、?. 搭配 ??、需要精确区分就显式判断、判有没有用 == null 别用 !value 的完整正解,以及其他混淆不存在与空值的坑,和不存在与值为零/空/否是两种本质不同的状态、零和空是确切而非缺席的信息、判断时要用精确标准区分缺失与空值的认知。本篇为踩坑复盘系列第 600 篇。

我用逻辑或给配置项设默认值,用户明明传了一个合法的 0,却被我当成"没传"替换成了默认值,因为 || 判断的是假值不是"是否缺失",而 0、空字符串、false 都是合法却为假的值:一次混淆"不存在"和"值恰好为空"的深度复盘

那个"用户配了却不生效"的投诉,让我重新认识了"设默认值"这件最日常的小事。我有个配置项 pageSize(分页大小),为了"用户没配时给个默认值 20",我写得很顺手:const pageSize = config.pageSize || 20;。功能一直好好的,直到有用户反馈:"我把 pageSize 配成了 0(我们业务里 0 表示'不分页、返回全部'),可系统还是按 20 分页,我的 0 根本不生效!"。我一看代码就傻眼了:config.pageSize 明明是 0(用户确实传了),可 0 || 20 的结果是 20——我的 || 把用户合法配置的 0,当成了"没配",替换成了默认值。复盘这件事,我才彻底想明白,后背发凉:问题出在我用 || 来做"缺失时给默认值",但 || 判断的根本不是"是否缺失",而是"是否为假值(falsy)"。JavaScript/TypeScript 里,a || b 的语义是:当 a 是"假值(falsy)"时,取 b;而"假值"不只有 nullundefined——0''(空字符串)、falseNaN 这些合法的、确实存在的值,也都是假值;我真正想表达的是"当 pageSize 没有提供(null/undefined)时,用默认值 20";可 || 会把"提供了但值是 0/空/false"也一并当成"该用默认值"——它混淆了"不存在"和"存在但值恰好为空/零/假"这两件本质不同的事;正确的做法,是用 空值合并运算符 ??:a ?? b 只在 a 是 nullundefined 时才取 b,而保留 0、''、false 这些合法值。根本原因是:|| 在左侧为任意假值(0/''/false/null/undefined/NaN)时都取默认值,而我想要的"缺失时给默认"只针对 null/undefined;|| 混淆了"不存在"和"值恰好为空/零/假",把合法的 0 误当成"没配"。问题的根,是用 || 设默认值——它对所有假值(含合法的 0/''/false)都取默认,混淆了"缺失"与"值为空/零/假";应该用只对 null/undefined 生效的 ??。这篇就把这次"|| 默认值陷阱"的坑,从头到尾复盘一遍。

故障现场:合法的 0,被当成"没配"

问题在于 || 把所有假值都当成"该用默认值":

// 我的写法: 用 || 给默认值(以为"没配就用默认")
const pageSize = config.pageSize || 20;

// 用户配置 pageSize = 0(业务上 0 表示"不分页"):
//   0 || 20  →  20    ✗ 用户合法的 0 被当成"没配", 替换成了 20!

// 更多被 || 误伤的合法值:
const name = input.name || "匿名";      // input.name = ""(用户清空了名字) → "匿名"(空字符串被替换!)
const count = data.count || 10;          // data.count = 0(真的是0个) → 10(0被替换!)
const enabled = opts.enabled || true;    // opts.enabled = false(用户想关闭) → true(false被替换! 关不掉)
const price = item.price || 99;          // item.price = 0(免费商品) → 99(免费变收费!)

/*
为什么 || 会误伤:
  - a || b 的语义: 当 a 是【假值 falsy】时取 b, 否则取 a;
  - JS/TS 的"假值(falsy)"有6个: false、0、''(空串)、null、undefined、NaN;
    (注意: 0、''、false 都是【合法的、确实存在的值】, 但它们是 falsy!)
  - 我想表达的"没提供 → 用默认"只针对 null/undefined;
  - 但 || 把 0、''、false 也一并当成"该用默认" → 误伤了这些合法值。

|| 和 ?? 的区别(关键):
  a || b   : a 为任意 falsy(false/0/''/null/undefined/NaN) 时取 b;
  a ?? b   : a 为 null 或 undefined 时才取 b(保留 0/''/false 等合法假值)  ← 设默认值该用这个;

  0 || 20      → 20   (0被当假值)
  0 ?? 20      → 0    (0是合法值, 保留)  ✓
  '' || 'x'    → 'x'
  '' ?? 'x'    → ''   ✓
  false || true → true
  false ?? true → false  ✓
  null ?? 20   → 20   (null才用默认)  ✓

★ 核心: || 判的是"是否假值", ?? 判的是"是否null/undefined(是否缺失)";
  "设默认值"想表达的是"缺失时给默认", 该用 ??; 用 || 会把合法的 0/''/false 误当成缺失。
  本质: 别混淆"不存在(缺失)"和"存在但值恰好是空/零/假"。

看着 0 || 20 === 20 这个我以前从没多想过的表达式,我又懊恼又恍然:"我一直用 || 设默认值,从来没出过事——因为以前那些配置项的合法值恰好都不包含 0、空、false……直到这个 pageSize 真的允许配 0,这个坑才暴露。原来我一直把'假值'和'没提供'当成一回事了。"这个坑最隐蔽的地方在于:绝大多数时候是对的——只要那个配置项的合法值不包含 0/''/false,||?? 表现就一样,你用 || 一辈子都不会出错;它只在"0/空串/false 是一个合法的、有意义的值"时才暴露,而这种 case 往往是少数、边界场景,测试容易漏下面就来拆解,默认值到底该怎么设。

第一件事:搞懂 falsy、|| 与 ??

我顺着这次事故,把假值、空值合并和"缺失 vs 空值"彻底理清了。

|| 和 ?? 到底差在哪? "设默认值"该用哪个?

【核心: ||在左侧为任意假值(false/0/''/null/undefined/NaN)时取默认; ??只在null/undefined时取默认;
   "缺失时给默认"该用??(保留合法的0/''/false); ||混淆了"不存在"和"值恰好为空/零/假", 别用它设默认】

1. falsy(假值)是哪些: JS/TS里 6 个值在布尔上下文为假:
   false、0(及-0、0n)、''(空字符串)、null、undefined、NaN;
   关键: 0、''、false 是【合法存在的值】, 但它们是 falsy!

2. a || b: 左侧为【任意假值】时取右侧
   - 0 || x → x;  '' || x → x;  false || x → x;  null/undefined || x → x;
   - 适合: "左侧是任何'空/假/无效'值时都用兜底"(确实想把0/''也当无效时);
   - 不适合: "只想在'没提供'时给默认"(会误伤合法的0/''/false)。

3. a ?? b: 左侧为【null 或 undefined】时才取右侧(空值合并, ES2020)
   - 0 ?? x → 0;  '' ?? x → '';  false ?? x → false;  null/undefined ?? x → x;
   - 适合: "设默认值"——只在"真的没提供(null/undefined)"时兜底, 保留合法的0/''/false。

4. 配套的 ?.(可选链): obj?.prop —— obj是null/undefined时短路返回undefined, 不报错;
   常和 ?? 搭配: const v = obj?.prop ?? defaultVal;  // 安全取值 + 缺失给默认。

5. 怎么选:
   - "设默认值/只关心是否提供" → 用 ??(只对 null/undefined 生效);
   - "想把一切空/假值都兜底"(明确包括0/'') → 才用 ||;
   - 大多数"给默认值"的场景, 想要的是 ??, 而非 ||。

6. 本质: 区分"不存在(absence)"和"值恰好为空/零/假(empty/zero/false)"
   - "用户没配 pageSize"(undefined) 和 "用户把 pageSize 配成 0"(0)是两回事;
   - 前者该用默认, 后者该尊重用户的0; || 把两者混为一谈, ?? 才区分得开。

一句话: ||在左侧为任意假值(含合法的0/''/false)时取默认、混淆了缺失与空值; ??只在null/undefined时取默认、
   保留合法假值; "设默认值"绝大多数该用??; 本质是别把"不存在"和"存在但值为空/零/假"混为一谈。

这套认知,是整个坑的根。falsy 是哪些:false、0、''、null、undefined、NaN——其中 0、''、false 是合法存在的值但也是 falsya || b:左侧任意假值时取右侧——会误伤合法的 0/''/falsea ?? b:左侧 null/undefined 时才取右侧(空值合并)——保留合法假值,适合设默认值配套 ?.:可选链安全取值,常与 ?? 搭配怎么选:设默认值/只关心是否提供→用 ??;想把一切空/假都兜底→才用 ||本质:区分"不存在(undefined)"和"值恰好为空/零/假(0/''/false)"——"没配 pageSize"和"配成 0"是两回事一句话:|| 在左侧为任意假值(含合法的 0/''/false)时取默认、混淆了缺失与空值;?? 只在 null/undefined 时取默认、保留合法假值;"设默认值"绝大多数该用 ??;本质是别把"不存在"和"存在但值为空/零/假"混为一谈。

第二件事:正解——设默认值用 ??,精确区分缺失与空值

知道了 || 误伤合法假值,正解就清楚了:设默认值用 ??,需要更精确就显式判断。

// 正解1: 设默认值用 ??(只在 null/undefined 时取默认)——本次该做的
const pageSize = config.pageSize ?? 20;     // ✓ 0 ?? 20 → 0, 保留用户合法的0
const name = input.name ?? "匿名";          // ✓ '' ?? '匿名' → '', 保留空字符串
const enabled = opts.enabled ?? true;       // ✓ false ?? true → false, 尊重用户关闭
const price = item.price ?? 99;             // ✓ 0 ?? 99 → 0, 免费就是免费

// 正解2: 安全取值 + 默认, ?. 和 ?? 搭配
const v = config?.page?.size ?? 20;         // config或page缺失时安全短路, 最终缺失才用20

// 正解3: 需要"区分多种空"时, 显式判断(别依赖 falsy 的笼统)
//   - 想"只有undefined才用默认, null表示'显式置空'要保留":
const x = (config.value === undefined) ? defaultVal : config.value;
//   - 想"空字符串也算没提供"(确实想把''当缺失): 那才该显式判断或用 ||(并写注释说明意图)
const title = (input.title?.trim()) ? input.title : "默认标题";  // 显式: 空白也算没提供

// 正解4: 真想用 || 时, 确认"把 0/''/false 也兜底"是你的本意
//   const retry = config.retry || 3;  // 只有当"retry=0也想用3"时才对; 若0是合法值(不重试)就错!
//   → 用 || 前问: 这个值会不会有合法的 0/''/false? 会, 就用 ??。

// 正解5: TypeScript 帮你——开 strictNullChecks, 类型区分 T | undefined
//   - 类型上把"可能缺失"标成 T | undefined, 逼你处理缺失情况;
//   - 配合 ?? / ?. 做安全的缺失处理, 类型和运行时一致。

// 小结对照:
//   想"缺失才默认, 保留0/''/false"  → 用 ??   (绝大多数设默认值场景)
//   想"任何空/假值都兜底"           → 用 ||   (确认包括0/''是本意时)
//   想"精确区分undefined/null/空串" → 显式 === 判断

// 核心: 设默认值用 ??(只对null/undefined生效), 保留合法的0/''/false; 用||前确认是否真想兜底一切假值;
//   精确区分缺失与空值; 开strictNullChecks让类型帮你识别"可能缺失"。

这套正解的关键,是用对运算符,精确表达"我到底想在什么情况下用默认值"设默认值用 ??:只在 null/undefined 时取默认,保留 0/''/false 这些合法值——这正是本次该做的。?. 和 ?? 搭配:安全取值 + 缺失给默认。需要区分多种空就显式判断:想区分 undefined/null/空串时,用 === undefined 等显式判断,别依赖 falsy 的笼统。真想用 || 时确认本意:用 || 前问"这个值会不会有合法的 0/''/false",会就用 ??。开 strictNullChecks:让类型把"可能缺失"标出来、逼你处理。

第三件事:其他几个"混淆不存在与空值"的坑

顺着这次 || 默认值,我把"把'没有'和'有但为空/零'混为一谈"的几类坑也一并理了:

几类"混淆不存在与空/零值"的坑:

坑1: if (!value) 判断"有没有"——!0、!''、!false 都为true, 把合法的0/''/false误判成"没有";
   正解: 判存在用 value == null(同时判null/undefined) 或 value === undefined; 别用 !value。

坑2: 后端返回字段缺失 vs 值为null vs 值为0——三种不同含义被前端用 || 抹平;
   正解: 想清字段语义; 缺失/null/0 各代表什么, 分别处理。

坑3: 数据库 NULL vs 空字符串 vs 0——SQL里 NULL 表示"未知/无值", 和 '' 、0 不同;
   WHERE col = '' 查不到 NULL; COUNT(col) 不计 NULL; 别混淆。

坑4: 表单"未填" vs "填了空"——用户没填(undefined) 和 填了空格/清空(''), 业务含义可能不同;
   正解: 按业务区分, 别一律当"没填"。

坑5: Map/对象 "没有这个key" vs "key存在但值是undefined/0"——
   obj.key 取到undefined, 分不清是"没这key"还是"值就是undefined"; 用 'key' in obj / map.has(key)区分。

坑6: 计数/金额的 0 被当"无数据"——0个、0元 是确切的数据, 不是"没数据"; 别用 || 或 !value 误判。

共同的根: "不存在/没有/未提供(null/undefined/缺失)" 和 "存在但值恰好是空/零/假(0/''/false/空集)"
   是两种【本质不同】的状态, 却常被一个笼统的判断(falsy、||、!value)混为一谈;
   而 0、''、false、空集 往往是【合法的、有确切含义的值】——把它们误当"没有", 就会丢失/篡改真实信息。

这些坑看似不同,根却是同一个:"不存在/没有(null/undefined/缺失)"和"存在但值恰好是空/零/假(0/''/false)"是两种本质不同的状态,却常被一个笼统的判断(falsy、||!value)混为一谈;而 0、''、false 往往是合法的、有确切含义的值,误当"没有"就会丢失或篡改真实信息认清这个根("区分'缺失'与'值为空/零/假'"),就能避开一大类"把合法的零/空当成无效"的判断错误。

第四件事:|| vs ?? / falsy 行为——两张对照表

我把 || 和 ?? 对各种值的行为、以及该用哪个,整理成对照表,贴在了团队的 TS 规范里:

左侧值 a a || b a ?? b
0 b(误伤!) 0(保留)
''(空串) b(误伤!) ''(保留)
false b(误伤!) false(保留)
NaN b NaN(保留)
null b b
undefined b b
正常值(如 5、'x') a a
需求 该用 原因
缺失时给默认,保留 0/''/false ?? 只对 null/undefined 生效
把一切空/假都兜底(确认含 0/'') || 对所有 falsy 生效
安全取嵌套值 + 默认 ?. + ?? 短路 + 缺失兜底
区分 undefined / null / 空串 显式 === falsy 太笼统
判"有没有这个值" == null 或 === undefined 别用 !value

这两张表的核心,第一张是对 0、''、false 这三个"合法却为假"的值,|| 会误伤、?? 会保留——这正是它俩的关键分野;第二张是"设默认值"绝大多数该用 ??,只有"明确想把 0/'' 也当无效"时才用 ||。记住一条:给默认值时,先问"这个值会不会有合法的 0/空/false"——会,就必须用 ??

第五件事:关于 || / ?? / 空值的几组容易想当然的认知

这次事故也让我厘清了几组关于默认值和空值的、容易想当然的概念:

直觉以为 实际上
|| 就是"没值时给默认" 是"假值时给默认",0/''/false 也算假值
0、''、false 算"没有值" 是合法存在的值,只是 falsy
|| 和 ?? 差不多 对 0/''/false 行为完全相反
!value 能判"有没有" !0、!''、!false 都为 true,会误判
用 || 一直没出错说明它对 是合法值恰好没包含 0/''/false 而已
字段缺失和值为 null/0 一回事 三种不同状态,业务含义可能不同
默认值用哪个无所谓 选错会篡改用户合法的 0/空/false

这张表里,我栽的是第一行和第二行:把"||"理解成了"没值时给默认",又把合法的 0 当成了"没有值",结果把用户精心配置的 0 给替换掉了厘清这些,核心是一个意识:"有没有提供一个值(存在性)"和"这个值本身是什么(包括它可能是 0/空/false)"是两个维度;|| 用"是否假值"粗暴地把它们搅在一起,?? 才精确地只判"是否缺失";给值设默认、做空判断时,要清楚自己究竟在判哪一个。

第六件事:设默认值 / 做空判断时,我现在的自检习惯

现在每当我要给一个值设默认、或判断它"有没有",我都会先按这张图问自己:

这张图的精髓,是"可能有合法0/空就用??、判有没有用==null别用!value"先问会不会有合法的 0/空/false(会就用 ??)、路径会不会缺失(会就配 ?.)、是不是在判有没有(是就用 == null)。这套习惯,让我从"设默认随手 ||"变成了"精确区分缺失与空值"——核心始终是:|| 对任意假值(含合法 0/''/false)取默认、混淆缺失与空值;?? 只对 null/undefined 取默认、保留合法假值;设默认值绝大多数该用 ??,别把"不存在"和"值为空/零/假"混为一谈。

我立下的几条规矩

这场"合法的 0 被默认值替换"的事故,换来了我写 TS/JS 时,刻进骨子里的几条铁律:

  1. || 判的是"是否假值(falsy)",?? 判的是"是否 null/undefined(是否缺失)"。
  2. falsy 有 6 个:false、0、''、null、undefined、NaN;其中 0、''、false 是合法存在的值。
  3. "设默认值"绝大多数该用 ??,保留合法的 0/''/false;别用 || 误伤它们。
  4. 用 || 前问:这个值会不会有合法的 0/''/false?会,就必须用 ??。
  5. 安全取嵌套值 + 默认,用 ?. 搭配 ??;要精确区分 undefined/null/空串用显式 ===。
  6. 判"有没有"用 == null 或 === undefined,别用 !value(会误判 0/''/false)。
  7. 区分"不存在(缺失)"和"存在但值为空/零/假"——它们是两种不同状态、含义可能不同。

附:一个区分"缺失/null/空值"的小工具

借这次的坑(这也是本系列第 600 篇里程碑),我给团队写了几个语义明确的小工具,把"缺失""为空""给默认"这几种意图从函数名上就分开,杜绝 || 的歧义。

// 明确区分三种"空"语义, 让调用处一眼看出意图

/** 是否"缺失"(没提供): 只有 null / undefined 算 —— 对应 ?? 的语义 */
function isMissing(v: unknown): v is null | undefined {
  return v === null || v === undefined;
}

/** 是否"空"(广义): 缺失, 或空串/空数组/空对象(但 0 和 false 不算"空"!) */
function isBlank(v: unknown): boolean {
  if (isMissing(v)) return true;
  if (typeof v === "string") return v.trim() === "";
  if (Array.isArray(v)) return v.length === 0;
  // 注意: 0 和 false 是合法值, 不算 blank
  return false;
}

/** 缺失时给默认(保留 0/''/false), 等价于 ?? 但语义更显眼 */
function withDefault(v: T | null | undefined, def: T): T {
  return isMissing(v) ? def : v;
}

// 用法: 意图清晰, 不会再误伤合法的 0/''/false
const pageSize = withDefault(config.pageSize, 20);   // 0 → 0(保留), undefined → 20
const enabled = config.enabled ?? true;              // false → false(保留)
if (isMissing(input.name)) { /* 真的没提供名字 */ }
if (isBlank(input.name))   { /* 没提供或填了空白 —— 这是另一种判断, 按需选 */ }

// 原则: 把"缺失(missing)""空白(blank)""给默认(withDefault)"这三种【不同的意图】,
//   用不同的、名字自解释的函数表达出来; 让代码读起来就知道"这里到底在判哪种空",
//   而不是用一个笼统的 || / !value 把所有"空"搅在一起、留下误伤合法值的隐患。

这套小工具的价值,在于把"缺失"和"空白"和"给默认"这几种容易被 || 搅在一起的不同意图,从函数名上就清清楚楚地分开:读到 isMissing 就知道"只判没提供"、读到 isBlank 就知道"连空白也算"、读到 withDefault 就知道"保留 0/''/false 的兜底"。把"区分无与空"这个认知,固化进了 API 的名字里。

写到这篇,正好是我这个「踩坑复盘」系列的第六百篇了。回头看这一路记录的坑——从空指针、并发竞态,到缓存、事务、微服务,再到大模型和智能体——它们的技术细节天差地别,但有一条线越来越清晰:绝大多数线上事故,根子都不在「不会用某个高深特性」,而在「对一个看似简单、自以为懂了的东西,藏着一个没察觉的前提或边界」。就像这次的 ||:谁不会用逻辑或呢?可恰恰是这种「太熟悉、从不多想」的地方,藏着「它判的是假值不是缺失」这个被我忽略了很久的前提。所以我越来越相信:真正的工程能力,不是记住多少冷僻 API,而是对每一个「习以为常」的东西,都保有一份「它到底是怎么定义的、边界在哪、我有没有想当然」的较真。这六百次较真,值了。

写在最后

回头看,这场由"用 || 设默认值"引发的、把用户合法的 0 替换掉的事故,真正教给我的,远不止"设默认值用 ??"这一个技巧。它让我对"'一样东西不存在' 和 '它存在、只是值恰好是零/空/否', 是两种本质不同的状态; 把它们用一个笼统的标准混为一谈, 就会把'确切的零'误读成'什么都没有'——而''恰恰是一个确切的、有意义的回答",有了一次刻骨的体会。我栽跟头,是因为我用一个粗糙的标准("是不是假值"),去回答一个精确的问题("用户到底提供了没有")——我把"真假(truthy/falsy)"当成了"有无(存在/缺失)";可这两者根本不是一回事: 一个值可以"确实存在", 同时"为假/为零/为空"——用户配的那个 0, 是一个响亮而确切的"我要不分页", 不是"沉默的没回答";我却用 || 这把粗筛子, 把"确切的 0"和"真正的没提供"一起筛掉了, 当成了"用户没说话, 我替他做主"这让我领悟到一个关于"无、零与空"的深刻认知:"没有(不存在)"和"零 / 空 / 否(存在但为最小/空白/否定值)"是必须分清的两种状态——"0 不是没有, '空字符串'不是没填, 'false'不是没表态, '空列表'不是没查到"; 它们都是"确切的、携带信息的回答", 而非"信息的缺席";把"零/空/否"误当成"没有", 是一类极其普遍、且常造成数据失真的错误——它会用一个默认值/兜底, 悄悄抹掉用户/数据本来确切表达的''; 而在很多场景里, "0 个""0 元""明确选择关闭""故意留空"恰恰是最重要、最不该被篡改的信息这给了我一种处理"空与无"时的清醒:每当我要判断"一个东西有没有值"或给它兜底时,要先分清"我要排除的, 究竟是'它不存在', 还是'它存在但为零/空/否'?"——对于"零/空/否也是合法且有意义的值"的场景, 要用精确的标准(?? == null)只针对"真正的缺失", 而不是用粗糙的'真假'把合法的零一起误杀;"尊重'零、空、否'作为确切回答的地位, 别把它和'没有'混为一谈",是避免悄悄篡改真实信息的关键认清不存在与值为零/空/否是两种本质不同的状态、零和空是确切而非缺席的信息、判断时要用精确标准区分缺失与空值——这,是我用一次 || 默认值的事故,换来的、关于 TypeScript、也关于如何对待"无、零与空"的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次给配置项设默认值时,把那个 || 换成 ??、稳稳护住用户那个合法的 0,那我对着那条"我配了 0 却不生效"的用户反馈排查的这段时间,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我在 C# 里打开了一堆文件流和数据库连接用完就不管了,以为有垃圾回收会自动清理,结果跑久了报 too many open files、连接池也满了,因为 GC 根本不负责释放这些非托管资源的深度复盘

2026-6-3 1:25:10

技术教程

我给 AI Agent 配了三十多个工具想让它无所不能,结果它反而经常选错工具、在几个功能相近的工具间反复横跳、甚至漏掉该用的那个,工具给得越多任务完成得越差的深度复盘

2026-6-3 1:37:22

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索