[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-rust-196-turns-ranges-into-safer-copies-zh":3,"article-related-rust-196-turns-ranges-into-safer-copies-zh":30,"series-tools-29e9abee-1972-4b0f-8994-ce27c006a5f3":75},{"id":4,"slug":5,"title":6,"content":7,"summary":8,"source":9,"source_url":10,"author":11,"image_url":12,"cover_image":12,"category":13,"language":14,"translated_content":11,"related_article_id":15,"keywords":16,"key_takeaways":22,"views":26,"created_at":27,"published_at":28,"topic_cluster_id":29},"29e9abee-1972-4b0f-8994-ce27c006a5f3","rust-196-turns-ranges-into-safer-copies-zh","Rust 1.96 讓 range 變可複製","\u003Cp data-speakable=\"summary\">\u003Ca href=\"\u002Ftag\u002Frust\">Rust\u003C\u002Fa> 1.96.0 把 range 改成更適合複製與保存的型別，順手拆掉一個常見的 Iterator 陷阱。\u003C\u002Fp>\u003Cp>我用 Rust 一陣子了，越寫越不敢相信「看起來很簡單」的東西。range 就是那種我原本以為最沒戲的東西：\u003Ccode>0..n\u003C\u002Fcode>、\u003Ccode>a..=b\u003C\u002Fcode>，直覺上就是一段範圍嘛，結果一塞進 helper、一放進 struct、一想重複用，ownership 就開始跟我鬧脾氣。它明明像資料，卻又帶著 iterator 的影子，寫起來不算爆炸，但每次都會卡一下。這種卡法最煩，因為你不能說它錯，只能說它很欠修。\u003C\u002Fp>\u003Cp>我最受不了的是，這東西在腦中應該是「可保存、可傳遞、可複製」的值，實際上卻常常逼你先拆成 start\u002Fend，再自己補回語意。那不是優雅，那是 workaround。Rust 平常很少讓我這麼不耐，但 range 這件事真的拖太久。直到我看到 Rust 1.96.0 這次把新 range 型別收進來，我才覺得：啊，終於有人承認這東西本來就不該長得像半個 iterator。\u003C\u002Fp>\u003Cp>我這次是從 Paul Krill 在 InfoWorld 的文章 \u003Ca href=\"https:\u002F\u002Fwww.infoworld.com\u002Farticle\u002F4191267\u002Frust-introduces-new-range-types.html\">Rust introduces new Range types\u003C\u002Fa> 看到線索的。原始資訊裡沒有給觀看數、書籤數或 star 數，所以我不亂掰。重點不是數字，是 Rust 1.96.0 \u003Ca href=\"https:\u002F\u002Fblog.rust-lang.org\u002F2025\u002F\">release notes\u003C\u002Fa> 背後那個很務實的整理：把「range 當資料」和「range 當 iterator 狀態」分開，別再混著玩。\u003C\u002Fp>\u003Ch2>Rust 終於承認：range 不該同時是資料和狀態\u003C\u002Fh2>\u003Cblockquote>It is a footgun to implement both Iterator and Copy on the same type.\u003C\u002Fblockquote>\u003Cp>翻譯一下就是：同一個型別如果又能隨便複製、又自己帶著迭代狀態，遲早有人踩雷。這句話其實很直白，Rust 標準庫這次等於是在說，舊的 range 設計把兩件本來不同的事硬塞在一起，方便是方便，但很容易把人搞到懷疑人生。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783189995404-zbpf.png\" alt=\"Rust 1.96 讓 range 變可複製\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>我自己最常碰到的就是把 range 放進 \u003Ca href=\"\u002Ftag\u002Fapi\">API\u003C\u002Fa> 之後，心裡想它只是個「區間描述」，結果用了幾層之後，某個地方把它當成 iterator 消耗掉了。那種 bug 不會很吵，甚至不會立刻炸，只是讓你在後面某個地方發現東西怎麼少了。這比直接編譯失敗還煩，因為它會讓你先相信自己寫對了。\u003C\u002Fp>\u003Cp>Rust 1.96.0 的方向很清楚：新的 range 型別走 \u003Ccode>IntoIterator\u003C\u002Fcode>，不是直接把 range 本體做成 iterator。白話講就是，range 先是一個值，需要迭代時再生出 iterator。這個切法很重要，因為它讓「我想複製這個範圍」和「我想跑這個範圍」不再互相打架。\u003C\u002Fp>\u003Cp>實操上，我現在會這樣想：如果你的型別是拿來描述事情，讓它像資料；如果你的型別是拿來執行事情，讓它像狀態。兩種責任混在一起，後面一定會有人來收拾殘局。Rust 這次只是把殘局先收了。\u003C\u002Fp>\u003Cul>\u003Cli>可重用的描述，用 value 表示。\u003C\u002Fli>\u003Cli>會被消耗的流程，用 iterator 表示。\u003C\u002Fli>\u003Cli>兩者要轉換，就明講，不要偷偷混血。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>\u003Ccode>core::range\u003C\u002Fcode> 其實是在把 API 拉回正常\u003C\u002Fh2>\u003Cp>Rust 1.96.0 把新的 range 型別放進 \u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fcore\u002Frange\u002Findex.html\">\u003Ccode>core::range\u003C\u002Fcode>\u003C\u002Fa>，像 \u003Ccode>Range\u003C\u002Fcode>、\u003Ccode>RangeFrom\u003C\u002Fcode>、\u003Ccode>RangeInclusive\u003C\u002Fcode> 這些都變成更適合當資料的版本。這不是在加花樣，這是在把命名和用途對齊。以前你看到 \u003Ccode>0..10\u003C\u002Fcode>，腦中以為自己拿到的是一個乾淨的區間；實際上它帶著歷史包袱，像穿西裝但裡面藏著跑步鞋。\u003C\u002Fp>\u003Cp>翻譯一下就是：標準庫現在終於給「range 作為值」一個正經住址。這件事看起來很小，但對寫 library 的人很有差。因為你要的是一個能存、能傳、能 copy 的 range，不是某個已經開始消耗狀態的怪東西。新 namespace 的好處是，你在 \u003Ca href=\"\u002Ftag\u002Fcode-review\">code review\u003C\u002Fa> 時可以很直接地講：「這裡用 \u003Ccode>core::range\u003C\u002Fcode>，因為它就是拿來當值的。」\u003C\u002Fp>\u003Cp>我以前在做一個內部工具時，也遇過類似問題：我們把「區間」和「游標」混在同一個 struct，結果大家都要先猜現在到底是描述狀態，還是已經進行到一半。那套設計後來只剩兩種用途：debug 時讓人煩，和 migration 時讓人更煩。Rust 這次其實是在幫大家少走一遍這種冤枉路。\u003C\u002Fp>\u003Cp>實操寫法很簡單：只要你的 API 是要讓使用者把範圍拿來保存、比對、轉傳，就把它當資料型別設計。不要一開始就把 iterator 行為塞進去。能分開就分開，別貪圖少一個型別，最後多一堆註解。\u003C\u002Fp>\u003Cul>\u003Cli>命名先對齊使用者的心智模型。\u003C\u002Fli>\u003Cli>舊行為保留，但新行為要有清楚落點。\u003C\u002Fli>\u003Cli>文件直接寫「這是值，不是狀態」。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>真正省事的是：你不用再硬拆 start\u002Fend\u003C\u002Fh2>\u003Cp>InfoWorld 提到，這次穩定下來之後，slice accessors 可以放進 \u003Ccode>Copy\u003C\u002Fcode> 型別裡，而不用先把 start\u002Fend 拆開。這句話很技術，但意思很白：以前你想把一段範圍當成一個值帶著走，常常得先把它拆成兩個欄位，等於自己把語意打碎再縫回去。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783189997884-nmx3.png\" alt=\"Rust 1.96 讓 range 變可複製\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>也就是說，Rust 現在\u003Ca href=\"\u002Fnews\u002Ffeaturedcustomers-ranks-21-mlops-vendors-customer-success-zh\">比較\u003C\u002Fa>像是在承認：很多時候你要的不是兩個數字，你要的是「這一段」。把它拆掉只是為了迎合舊設計，並不是因為你的程式真的比較清楚。這種 workaround 我做過，做完只會得到一個看起來很務實、其實很醜的 struct。欄位多了，語意少了，後人還得猜你當初到底在怕什麼。\u003C\u002Fp>\u003Cp>我現在會把這件事當成一個設計檢查點：如果一個值在你的 API 裡會被反覆傳遞、複製、保存，那它最好能保持完整。不要逼使用者先拆成零件，除非 start 和 end 本來就各自有獨立意義。很多 API 之所以難懂，不是因為功能太複雜，是因為型別把本來單純的概念切碎了。\u003C\u002Fp>\u003Cp>實操寫法：你在設計自己的型別時，先問一句，使用者需不需要只把它當成一個區間？如果答案是要，那就直接給他一個可複製的 range-like value。真的要拆欄位，也請把拆開的理由寫清楚，不然下一個接手的人只會以為你在逃避設計。\u003C\u002Fp>\u003Cul>\u003Cli>能保留整體語意，就別先拆零件。\u003C\u002Fli>\u003Cli>欄位拆分只在各自有獨立意義時使用。\u003C\u002Fli>\u003Cli>讓型別本身就是答案，不要讓人猜。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>\u003Ccode>RangeInclusive\u003C\u002Fcode> 露出欄位，反而比較誠實\u003C\u002Fh2>\u003Cp>文章裡有一個我很喜歡的細節：新的 \u003Ccode>RangeInclusive\u003C\u002Fcode> 會把欄位公開，因為它不再需要藏 iterator 的 exhausted 狀態。這件事很像把一個原本硬撐著裝成熟的東西，終於拆掉多餘的面具。舊版之所以要把內部狀態藏起來，是因為它同時扮演了資料和 iterator，得防止大家亂摸；新版不用演了，欄位自然也不用藏那麼深。\u003C\u002Fp>\u003Cp>翻譯一下就是：當型別真的只是資料，公開欄位不一定是壞事。很多人一看到 public field 就先皺眉，但問題從來不是 public 本身，而是這個型別有沒有需要保護的隱性狀態。沒有的話，你把它包得跟保險箱一樣，只是在增加閱讀\u003Ca href=\"\u002Fnews\u002Fcalifornia-claude-deal-cuts-agency-ai-costs-half-zh\">成本\u003C\u002Fa>。\u003C\u002Fp>\u003Cp>我以前也很愛把東西全藏起來，覺得這樣比較「\u003Ca href=\"\u002Fnews\u002Fbooz-allen-openai-secure-ai-deployable-zh\">安全\u003C\u002Fa>」。後來才發現，很多時候那只是讓 API 變得更難用，順便把簡單問題做成黑盒。Rust 這次的做法很對我的胃口：如果型別是乾淨的資料，那就老實一點，別再靠封裝假裝自己很複雜。\u003C\u002Fp>\u003Cp>實操寫法很直接：設計資料型別時，先看你到底有沒有不想讓人碰的內部狀態。沒有，就別硬藏。你要保護的是不變式，不是你的心理安全感。\u003C\u002Fp>\u003Ch2>舊 range 還留著，這才是成熟的做法\u003C\u002Fh2>\u003Cp>Rust 1.96.0 沒有把舊的 range 直接整包炸掉。現在像 \u003Ccode>0..1\u003C\u002Fcode> 這種語法還是先走 legacy 型別，未來才會慢慢切到新的 range 家族。這種做法我很買單，因為它不是把大家丟下去重寫，而是先把新路鋪好，再慢慢把舊路標成 legacy。\u003Ca href=\"https:\u002F\u002Fwww.rust-lang.org\u002F\">Rust 官方網站\u003C\u002Fa> 一直都很擅長這種不粗暴的遷移。\u003C\u002Fp>\u003Cp>白話講就是：舊東西先活著，但別再假裝它是長期答案。這對大型生態系很重要，因為你不可能要求每個 crate、每個團隊、每個內部工具都同一天一起改完。真正麻煩的不是新舊並存，而是新舊並存卻沒有明確標示，最後大家都以為自己踩的是同一塊地板。\u003C\u002Fp>\u003Cp>我在公司內部做過一次型別遷移，最糟的版本就是「今天改完、明天全壞」。那種做法很爽，因為看起來乾淨，但實際上只有一小撮人覺得爽，其他人都在半夜補洞。Rust 這次選擇的路線比較像老司機：先告訴你哪裡是新路，哪裡是舊路，然後讓你自己慢慢切。\u003C\u002Fp>\u003Cp>實操寫法：如果你也在做 API 重構，請先把新舊邊界講清楚。保留舊介面可以，但命名要誠實，文件要寫明白，遷移步驟要有。別讓 legacy 假裝自己還是主線。\u003C\u002Fp>\u003Cul>\u003Cli>保留相容性，但不要美化舊設計。\u003C\u002Fli>\u003Cli>把 migration path 寫成使用者看得懂的步驟。\u003C\u002Fli>\u003Cli>新 API 要先有清楚的落點，再慢慢推舊 API 退場。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>這次順手加的 assertion macro，比 range 小一號但很實用\u003C\u002Fh2>\u003Cp>Rust 1.96.0 也加了 \u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fstd\u002Fmacro.assert_matches.html\">\u003Ccode>assert_matches!\u003C\u002Fcode>\u003C\u002Fa> 和 \u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fstd\u002Fmacro.debug_assert_matches.html\">\u003Ccode>debug_assert_matches!\u003C\u002Fcode>\u003C\u002Fa>，用來檢查值有沒有符合 pattern。這東西有用，但我不會把它當主菜。它比較像是把測試裡那些「我知道你應該長這樣」的判斷寫得更順手，失敗訊息也更好看。\u003C\u002Fp>\u003Cp>翻譯一下就是：你不用再手刻一堆 enum 比對，Rust 幫你把樣板碼收掉一點。這種改善我當然歡迎，因為它不改你的思考方式，只是少一點摩擦。range 的改動是在修模型，這個 macro 比較像是在修手感。\u003C\u002Fp>\u003Cp>我自己會把它放在測試和除錯用的地方，尤其是你在處理 enum、Result、Option 這類結構時，pattern 比對比手寫 if\u002Felse 更乾淨。只是別亂用到 production 邏輯裡，否則你只是把可讀性換成另一種形式的炫技。\u003C\u002Fp>\u003Cp>實操寫法：當你在測試裡關心的是「形狀」不是「精準值」時，用這兩個 macro。你會少寫很多樣板，失敗時也比較知道哪裡歪掉。\u003C\u002Fp>\u003Ch2>我真正想學的，是這套拆法\u003C\u002Fh2>\u003Cp>我看 Rust 1.96.0 這次 range 的整理，學到的不是「多了哪些型別」，而是它怎麼拆問題。它先承認舊設計把資料和狀態混在一起，再把新型別放到更誠實的 namespace，最後保留舊行為做過渡。這不是炫技，這是把一個長年不順眼的設計拆乾淨。\u003C\u002Fp>\u003Cp>白話講就是：如果你的 API 讓人常常懷疑自己是不是把東西用錯了，那多半不是使用者太笨，是你的型別責任分配有問題。Rust 這次把問題講得很直接，也很符合我平常在 code review 會碎念的點：能當資料就別裝成狀態，能複製就別逼人拆零件，能遷移就別假裝沒成本。\u003C\u002Fp>\u003Cp>我會把這次更新當成一個很好的設計範本。不是因為它多潮，而是因為它夠老實。老實地承認舊 API 有包袱，老實地把新概念放到對的位置，老實地讓使用者少踩一個坑。這種改法，才真的值得拿來抄。\u003C\u002Fp>\u003Ch2>可抄的模板\u003C\u002Fh2>\u003Cpre>\u003Ccode>## Rust 1.96.0 range 改動我怎麼解讀\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>Rust 1.96.0 把 range 從「像 iterator 的值」整理成「更像資料的值」。\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>我現在會這樣設計自己的型別：\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 如果是可複用的描述，用 Copy-friendly 的 value 表示\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 如果是會被消耗的流程，用 iterator 或明確的 state 表示\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 如果需要轉換，讓 IntoIterator 這種轉換層出現，不要把兩種責任塞進同一個型別\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>### 範例：把 range 當成資料存起來\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>use core::range::Range;\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>#[derive(Copy, Clone)]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>struct Window {\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>    bounds: Range&lt;usize&gt;,\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>impl Window {\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>    fn new(bounds: Range&lt;usize&gt;) -&gt; Self {\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>        Self { bounds }\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>    }\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>### 我自己的 migration checklist\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 先確認這個型別是「資料」還是「狀態」\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 能存就直接存，不要先拆 start\u002Fend\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 舊 API 保留，但命名要標示 legacy\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 測試裡想看 pattern，就用 assert_matches!\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre>\u003Ccode>- 文件裡直接寫清楚：這個型別會不會被消耗\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>這段模板是我根據 Rust 1.96.0 的 range 整理自己重寫的，不是原文照搬。原始來源主要是 InfoWorld 這篇 \u003Ca href=\"https:\u002F\u002Fwww.infoworld.com\u002Farticle\u002F4191267\u002Frust-introduces-new-range-types.html\">Rust introduces new Range types\u003C\u002Fa>，搭配 Rust 官方文件 \u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fcore\u002Frange\u002Findex.html\">core::range\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fstd\u002Fmacro.assert_matches.html\">assert_matches!\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fdoc.rust-lang.org\u002Fstd\u002Fmacro.debug_assert_matches.html\">debug_assert_matches!\u003C\u002Fa>。我拆解的是方法論，模板是我整理給\u003Ca href=\"\u002Ftag\u002F台灣開發者\">台灣開發者\u003C\u002Fa>直接拿去改的版本。\u003C\u002Fp>","Rust 1.96.0 把 range 拆成更像資料的型別，解掉 Iterator + Copy 的坑，讓你更安心地存、傳、複製範圍值。","www.infoworld.com","https:\u002F\u002Fwww.infoworld.com\u002Farticle\u002F4191267\u002Frust-introduces-new-range-types.html",null,"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783189995404-zbpf.png","tools","zh","a3df178b-7492-4b4b-8ab6-1de524c2fbdd",[17,18,19,20,21],"Rust","range","Iterator","Copy","core::range",[23,24,25],"Rust 1.96.0 把 range 從 iterator 狀態中拆出來，讓它更像可複製、可保存的資料型別。","新的 core::range 讓 API 設計更乾淨，避免 start\u002Fend 拆分和隱性消耗狀態。","這次更新最值得抄的不是語法，而是把資料與狀態分離、保留舊 API 但誠實標示 legacy 的遷移手法。",1,"2026-07-04T18:32:53.059717+00:00","2026-07-04T18:32:53.049+00:00","c3c88dd2-a940-438a-b359-0e5a24562273",{"tags":31,"relatedLang":34,"relatedPosts":38},[32],{"name":17,"slug":33},"rust",{"id":15,"slug":35,"title":36,"language":37},"rust-196-turns-ranges-into-safer-copies-en","Rust 1.96 turns ranges into safer copies","en",[39,45,51,57,63,69],{"id":40,"slug":41,"title":42,"cover_image":43,"image_url":43,"created_at":44,"category":13},"38959780-e00f-4a9f-afd1-a75f24732cd1","rustrover-2026-1-4-right-default-ide-rust-zh","RustRover 2026.1.4 是 Rust 團隊的正確預設 IDE","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783211564090-s3ei.png","2026-07-05T00:32:19.50775+00:00",{"id":46,"slug":47,"title":48,"cover_image":49,"image_url":49,"created_at":50,"category":13},"abe21472-cda7-491d-9d7b-f9f64e3154b3","claude-design-synced-prototypes-setup-zh","Claude Design 同步原型設定指南","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783191770382-4zms.png","2026-07-04T19:02:21.637665+00:00",{"id":52,"slug":53,"title":54,"cover_image":55,"image_url":55,"created_at":56,"category":13},"081e378e-a0d9-408b-95ab-003b476c67a5","ai-data-operations-vs-mlops-what-each-owns-zh","AI Data Ops 與 MLOps 的分工","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783168367881-i1cl.png","2026-07-04T12:32:19.522726+00:00",{"id":58,"slug":59,"title":60,"cover_image":61,"image_url":61,"created_at":62,"category":13},"351f5aa9-e7da-4676-a7f3-893336f79a92","opentag-turns-slack-threads-into-actions-zh","OpenTag 讓 Slack 對話變動作","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783148607976-8g9n.png","2026-07-04T07:02:50.017949+00:00",{"id":64,"slug":65,"title":66,"cover_image":67,"image_url":67,"created_at":68,"category":13},"5358fb05-efb5-4238-abc5-fb3933da13e7","gpu-vram-needed-llm-fine-tuning-2026-zh","2026 年 LLM 微調要多少 VRAM","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783128777725-3n1p.png","2026-07-04T01:32:33.595421+00:00",{"id":70,"slug":71,"title":72,"cover_image":73,"image_url":73,"created_at":74,"category":13},"9568ce15-1e27-450b-8c62-c6c97a94372d","claude-sonnet-5-shangshou-bushu-yu-pinggu-zh","Claude Sonnet 5 上手部署与评估","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1783125163927-v143.png","2026-07-04T00:32:19.271862+00:00",[76,81,86,91,96,101,106,111,116,121],{"id":77,"slug":78,"title":79,"created_at":80},"855cd52f-6fab-46cc-a7c1-42195e8a0de4","surepath-real-time-mcp-policy-controls-zh","SurePath 推出即時 MCP 政策控管","2026-03-26T07:57:40.77233+00:00",{"id":82,"slug":83,"title":84,"created_at":85},"9b19ab54-edef-4dbd-9ce4-a51e4bae4ebb","mcp-in-2026-the-ai-tool-layer-teams-use-zh","2026 年 MCP：團隊真的在用的 AI 工具層","2026-03-26T08:01:46.589694+00:00",{"id":87,"slug":88,"title":89,"created_at":90},"af9c46c3-7a28-410b-9f04-32b3de30a68c","prompting-in-2026-what-actually-works-zh","2026 提示工程，真正有用的是什麼","2026-03-26T08:08:12.453028+00:00",{"id":92,"slug":93,"title":94,"created_at":95},"05553086-6ed0-4758-81fd-6cab24b575e0","garry-tan-open-sources-claude-code-toolkit-zh","Garry Tan 開源 Claude Code 工具包","2026-03-26T08:26:20.068737+00:00",{"id":97,"slug":98,"title":99,"created_at":100},"042a73a2-18a2-433d-9e8f-9802b9559aac","github-ai-projects-to-watch-in-2026-zh","2026 必看 20 個 GitHub AI 專案","2026-03-26T08:28:09.619964+00:00",{"id":102,"slug":103,"title":104,"created_at":105},"a5f94120-ac0d-4483-9a8b-63590071ac6a","claude-code-vs-cursor-2026-zh","Claude Code 與 Cursor 深度對比：202…","2026-03-26T13:27:14.279193+00:00",{"id":107,"slug":108,"title":109,"created_at":110},"0975afa1-e0c7-4130-a20d-d890eaed995e","practical-github-guide-learning-ml-2026-zh","2026 機器學習入門 GitHub 實用指南","2026-03-27T01:16:49.712576+00:00",{"id":112,"slug":113,"title":114,"created_at":115},"bfdb467a-290f-4a80-b3a9-6f081afb6dff","aiml-2026-student-ai-ml-lab-repo-review-zh","AIML-2026：像課綱的學生實驗 Repo","2026-03-27T01:21:51.467798+00:00",{"id":117,"slug":118,"title":119,"created_at":120},"80cabc3e-09fc-4ff5-8f07-b8d68f5ae545","ai-trending-github-repos-and-research-feeds-zh","AI Trending：把 AI 資源收成一張表","2026-03-27T01:31:35.262183+00:00",{"id":122,"slug":123,"title":124,"created_at":125},"3ce6e6e2-bac5-463e-9f8d-45caabcc61f7","awesome-ai-for-science-research-tools-map-zh","AI 科研工具清單，開始像地圖了","2026-03-27T01:46:50.521945+00:00"]