<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Big Sky</title>
    <link>https://mattn.kaoriya.net/</link>
    <description>システム開発屋がひっそり語るぼやき</description>
    <language>ja</language>
    <generator>blosxom/2.1.2+dev</generator>
    <atom:link rel="self" href="http://mattn.kaoriya.net/index.rss" type="application/rss+xml" />
    <atom:link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
   <item>
     <title>書評『レジリエント・マネジメント』</title>
     <pubDate>Sat, 08 Nov 2025 20:44:00 +0900</pubDate>
     <link>https://mattn.kaoriya.net/etc/20251108204219.htm</link>
     
     <guid isPermaLink="true">https://mattn.kaoriya.net/etc/20251108204219.htm</guid>
     <description>
&lt;h3 id=&quot;はじめに&quot;&gt;はじめに&lt;/h3&gt;

&lt;p&gt;株式会社アットウェアの guyon
さんから献本頂きました。ありがとうございます。&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://amzn.to/4iIPmdX&quot;&gt;レジリエントマネジメント　荒波に立ち向かい、困難を乗り越えるチームの育て方&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本書はテクノロジー業界でマネージャーやリーダーとして、コーチングに関する講演や執筆を行っておられる
Lara Hogan 氏による書「Resilient Management」の翻訳本です。&lt;/p&gt;
&lt;p&gt;VimConf 2025 small の会場で、本書の翻訳を担当された guyon
さんから直接手渡しで頂き、帰りの新幹線で早速読み始めました。&lt;/p&gt;

&lt;h3 id=&quot;マネジメントに正解はない&quot;&gt;マネジメントに正解はない&lt;/h3&gt;

&lt;p&gt;実は僕は普段、こういった自己啓発本を読むことはまずありません。マネジメントをやられる方であればご理解いただけると思いますが、マネジメント業にはほぼほぼ完璧な答えがないからです。その場その場で起きる問題が異なり、同じ問題であっても人や組織の状況によって最適解が変わるため、巷の書籍などで紹介されている方法論をそのまま適用することに対して、どこかしら抵抗感を持っていたからです。特にマネジメントとはいわゆる「人」を扱う分野であり、「人間ハック」という言葉で表現されることもありますが、対話する相手の個性や感情、価値観を無視して一律の方法論を押し付けることに対して、強い違和感を覚えているからです。&lt;/p&gt;
&lt;p&gt;われわれは一部の成功事例を真似して「これをやればうまくいく」と信じてしまうことが多々ありますが、僕はそれらは生存者バイアスだと思っています。つまり、特定の文脈で偶然うまくいった方法を一般化しても、それが自分たちに当てはまるとは限らないとも思っています。&lt;/p&gt;
&lt;p&gt;しかし本書は、そのような僕の先入観に対して「そういうことばかりではないよ」と覆してくれたように思います。&lt;/p&gt;
&lt;p&gt;本当の「レジリエント・マネジメント」とは、人間をハックすることではなく、人間の多様性と限界を理解し、健全なバランスを取ることだからです。&lt;/p&gt;

&lt;h3 id=&quot;バランスと-biceps&quot;&gt;バランスと BICEPS&lt;/h3&gt;

&lt;p&gt;本書を読んでまず印象に残ったのは「バランスを取ることの大切さ」です。辞書で
Resilient (レジリエント)
を調べると「しなやかさ」や「回復力」という訳が出てきます。この言葉の通り、本書で強調されているのは「しなやかさ」そして「回復力」です。&lt;/p&gt;
&lt;p&gt;IT
エンジニアの皆さんであれば、開発を行っているチームや組織の状態が、急速に変化したり、不安定になることを日常的に経験されたことがあるでしょう。例えば、チームメンバの退職、チーム内の不仲、経営層の交代などによりチーム構成やリーダーシップが大きく変わるなどです。米国であればレイオフも起きるでしょう。このような状況では、チームの雰囲気が一変し、メンバ同士の信頼関係が揺らいだり、コミュニケーションが滞ったりすることがあると思います。&lt;/p&gt;
&lt;p&gt;また、プロジェクトの優先順位が突然変更されたり、新しい技術スタックへの移行が急に決まったりすることもあります。これにより、チームメンバが戸惑いを感じたり、モチベーションが低下したりすることがあります。そういった変化の中で、チームや組織がしなやかに対応し、問題に対して強い回復力を持つことが求められます。&lt;/p&gt;
&lt;p&gt;さらにチームとして継続的に成長するためには、個々に対するヒアリングやフィードバックが欠かせません。個々の評価を公平に、そして健全に行うことが重要です。メンターとして個々に対する関心や興味といった「好奇心」を持つことで、メンバの強みや課題を理解し、適切なサポートを提供できる様になります。&lt;/p&gt;
&lt;p&gt;対話の方法、メールを投げるタイミング、メールの量、そういったリアルな
Tips
だけでなく、起こりうるさまざまなケースで最悪の事態に陥らないために、普段どの様な心構えや行動が必要かといった具体的なアドバイスが提供されています。&lt;/p&gt;
&lt;p&gt;特に印象的だったのが、BICEPS
モデルの考え方です。人が安心して「しなやか」に働くためには、6つの基本的欲求
BICEPS があると書かれています。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Belonging（帰属）&lt;/li&gt;
&lt;li&gt;Improvement（成長）&lt;/li&gt;
&lt;li&gt;Choice（選択）&lt;/li&gt;
&lt;li&gt;Equality（公平）&lt;/li&gt;
&lt;li&gt;Predictability（予測可能性）&lt;/li&gt;
&lt;li&gt;Significance（意義）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;例えば、チームに帰属意識があり、発言や判断に自分の選択が反映され、扱われ方に公平さを感じ、将来がある程度見通せて、自分の仕事に意義を感じられるとき、人は自然と「レジリエント(しなやか)」になります。逆に、これらが欠けた組織では、変化へのしなやかさが失われ、硬直的になります。&lt;/p&gt;
&lt;p&gt;硬直的にならないためには普段からメンバの声を聞くことが重要です。マネジメントをしていると忘れがちですが、現場こそが最も多くの真実を知っているということは揺るぎません。上からの判断よりも、実際に手を動かしている人の感覚やデータを尊重することが、組織のしなやかさを支えると僕は思っています。&lt;/p&gt;

&lt;h3 id=&quot;チームの健全性を育てる&quot;&gt;チームの健全性を育てる&lt;/h3&gt;

&lt;p&gt;しかし現場の声を引き出すのは簡単ではありません。ツールやプロセスが複雑すぎると、逆にそれが障壁になります。Slack、Jira、といったツールを使っていかにうまくコミュニケーション環境とレポートラインを構築するかも重要です。こういったツール選びは新規参画者のオンボーディングにも影響します。例えば新規参画者のためを思って用意された導入資料が各所に散乱していたり、量が多いとかえって「覚えられるわけがない」と感じさせてしまうこともあります。こういった心理学的な配慮も、レジリエント・マネジメントには欠かせません。&lt;/p&gt;
&lt;p&gt;人間の脳は「予測」と「安全」を求めるようにできており、予測が外れるとストレスが生じます。だからこそ、組織がしなやかであるためには、BICEPS
のような心理的ニーズを満たしつつ、それでいて「不確実性にどう対処するか」をチームとして訓練する必要があるのです。&lt;/p&gt;
&lt;p&gt;レジリエントなマネジメントとは、個人の能力よりもチームの健全性に重きを置く考え方だと思いました。チームを育てるのは1人では無理なのです。誰かが視野を狭めた時、それを補い合うチームであればこそ、変化の波にもしなやかに対応できるはずです。&lt;/p&gt;

&lt;h3 id=&quot;おわりに&quot;&gt;おわりに&lt;/h3&gt;

&lt;p&gt;本書を通じて学んだのは「強さ」よりも「しなやかさ」を重んじる姿勢です。人と人の関係の中で健全な摩擦によりレジリエンスを育てていく。その考え方が、これからの不確実な時代を生き抜くために必要なアイテムだと感じました。&lt;/p&gt;
</description>
     <author>mattn.jp@gmail.com (mattn)</author>
   </item>
   <item>
     <title>VimConf 2023 Tiny に参加しました</title>
     <pubDate>Mon, 20 Nov 2023 00:49:00 +0900</pubDate>
     <link>https://mattn.kaoriya.net/software/vim/20231120003710.htm</link>
     
     <guid isPermaLink="true">https://mattn.kaoriya.net/software/vim/20231120003710.htm</guid>
     <description>
&lt;h2&gt;はじめに&lt;/h2&gt;
&lt;p&gt;11/18、東京秋葉原のアキバプラザで、4年ぶりとなる VimConf、「VimConf 2023 Tiny」が開催されました。&lt;/p&gt;
&lt;p&gt;今回、Kaoriya さんから「SoftwareDesign で執筆した内容で基調講演をして欲しい」とお願いされた際に、即答で OK をしましたが実は少し不安がありました。SoftwareDesign を事前に購入した人に同じ話を聞かせてしまうのは残念すぎないかという気持ちです。どうしようかとしばらく検討しましたが、SoftwareDesign の内容からスピンオフした内容にする事にしました。&lt;/p&gt;
&lt;p&gt;規模が少し小さいとは言え、せっかく楽しみにきて頂いてる皆さんに、残念に思われないようにしたい、少しでも「来て良かった」と思って貰えるイベントにしたと思い、テーマは変えないまま色々な Bram Moolenaar 氏のエピソードを盛り込んだつもりです。&lt;/p&gt;
&lt;p&gt;11/18 当日、僕は会場の受付で運営側としてノベルティの VimConf マスクを配布させて頂きました。(お気付きだっただろうか)&lt;/p&gt;
&lt;p&gt;事前の PC 接続テストで Ubuntu Linux がうまく HDMI 出力できず最終的に KaoriYa さんのノート PC をお借りする事になった事だけが残念です。&lt;/p&gt;
&lt;h2&gt;発表の感想&lt;/h2&gt;
&lt;p&gt;以下は各登壇者の発表の感想です。&lt;/p&gt;
&lt;h3&gt;Λlisue さん (Revolutionizing Vim/Neovim Plugin Development ~ An In-Depth Look into Denops)&lt;/h3&gt;
&lt;p&gt;Vim と deno を RPC で繋ぎ、TypeScript で実装を行う事で、Vim をロックさせず、なおかつ型のある安全な実装をできる Denops という仕組みを実装した、ありすえさんの発表。Denops が生まれた経緯などがわかりやすく解説されていた。&lt;/p&gt;
&lt;p&gt;Pros/Cons が説明されている点と、どんな物に Denops を適用すれば良いのかを解説していたのは良かった。AI との組み合わせはこれからの Vim 界隈でも増えていくと思いました。&lt;/p&gt;
&lt;h3&gt;ゴリラさん (Looking back at vim meetup)&lt;/h3&gt;
&lt;p&gt;ゴリラ.vim を発足した理由や、今も尚開催を継続しているモチベーションを説明いただきました。ゴリラさんの日頃からのモチベーションの高さは僕も皆も関心していて、逆にゴリラさんから熱いパワーを貰っている側面もあります。「まだ発表するには自分は早い」と言わずどんどん発表して欲しいとの事。次回開催は 12/13 です。次回開催は 12/13 です。(大事な事なので2度書きました)&lt;/p&gt;
&lt;h3&gt;大倉雅史さん (Developing a Vim plugin with Ruby, or when in Ruby do as the Rubyists do)&lt;/h3&gt;
&lt;p&gt;RSpec の使い勝手のよろしく無い部分を Vim で解決しようという話。英語での発表でありながらテンションの高さを表現されており素晴らしかった。個人的には LT の時の「マスタリング Vim」もテンション高くて良かったです。&lt;/p&gt;
&lt;h3&gt;kuu さん (Modern techniques for implements insert mode plugins / Why use IME within text editor?)&lt;/h3&gt;
&lt;p&gt;skkeleton の作者 kuu さんがインサートモード時の処理の難しさと skk.vim や eskk 等との比較なども。実は僕も Vim での SKK 実装を2回ほどやった経緯があり興味深く見せて頂きました。ちなみに SKK にチャレンジしたけど挫折した人は意外といるという知見を得ました。&lt;/p&gt;
&lt;h3&gt;aiya000 さん (Boost your vimrc with some template techniques!)&lt;/h3&gt;
&lt;p&gt;vimrc の基本的な構成の説明や、vital.vim が凄いという話をしていただきました。vimrc を書く上で便利な Lambda や辞書リテラル、メソッド記法、そして皆がまだ使ってないかもしれない String interpolation を解説して頂きました。僕個人もまだ String interpolation を使ってないのでどんどん使って行きたい。&lt;/p&gt;
&lt;p&gt;ほか懇親会でも沢山 LT をしてくれた方がいて、とても楽しい会でした。&lt;/p&gt;
&lt;h2&gt;ところで&lt;/h2&gt;
&lt;p&gt;新型コロナウィルスが蔓延してテック系イベントが開催されなくなってはや数年、今年は開催しようという運営の判断で VimConf 2023 を開催しました。ただしギリギリまで決めかねていた事もあり、また4年という歳月が過ぎた事で、正直テキストエディタのシェアも変わっている可能性もあり、正直もしかするとユーザの多くが VSCode に移ってしまったかもしれないという一抹の不安もありました。運営としては極力、力を入れすぎない開催にしようという判断で VimConf 2023 Tiny と名付け、幾らか規模を小さくして開催する事にしました。&lt;/p&gt;
&lt;p&gt;しかしその不安はすぐに間違っていた事に気付かされました。VimConf 2023 Tiny のチケットはあっという間に完売し、さらに SNS で「チケット買えなかった」「もっと参加人数を増やして欲しかった」と言われるほどでした。&lt;/p&gt;
&lt;p&gt;そして何よりも Vimmer の皆さんの熱量が何も変わっていない事にとても嬉しく感じました。まだ VimConf を終えた直後ですが「また VimConf やろう」という気持ちも湧きました。そして今回、LT に Vim 好きの中学生がエントリしてくれました。メタバースで Vim の集会をやってる話をしてくれました。Vim 好きがちゃんと若い人たちにも育っているのを感じました。いい話すぎる。&lt;/p&gt;
&lt;p&gt;今回、参加される皆さんにはマスクの着用をお願いしました。その為にマスクをノベルティとして配布しました。スタッフとして考えた末のノベルティでしたが当日、皆さんちゃんとマスクを付けて頂いていて本当に嬉しかったです。ありがとうございました。&lt;/p&gt;
&lt;p&gt;今は無事 VimConf を復活させる事ができた安堵感でいっぱいです。&lt;/p&gt;
</description>
     <author>mattn.jp@gmail.com (mattn)</author>
   </item>
   <item>
     <title>Go 言語プログラミングエッセンスという本を書きました。</title>
     <pubDate>Mon, 20 Feb 2023 22:51:00 +0900</pubDate>
     <link>https://mattn.kaoriya.net/software/lang/go/go-programming-essense.htm</link>
     
     <guid isPermaLink="true">https://mattn.kaoriya.net/software/lang/go/go-programming-essense.htm</guid>
     <description>

&lt;p&gt;2023/3/12 発売です。&lt;/p&gt;



&lt;p&gt;Go が発表された当初から Go を見続けて来たので ずいぶん時間が経った気がします。僕なりにいろいろな活動をして来ました。Go 本体や周辺ツールへのコントリビュート、イベント登壇、雑誌への記事の投稿や「&lt;a href=&quot;https://amzn.to/3IEhbE3&quot;&gt;みんなのGo言語&lt;/a&gt;」の共著など。&lt;/p&gt;

&lt;p&gt;あらゆる活動が Go づくめで刺激的でした。Go で得たものも沢山あります。そして Go を使う人も想像していた以上に沢山増えました。Go に関して書かれたブログ、Go の求人、今では大学で Go を教えているところもあるくらいです。Go を知った事で僕のプログラミング人生はずいぶん変わりました。それまでは何を作るにしてもC言語をメイン言語として使ってきましたが、今や新しいアプリケーションを書くのであればほぼほぼ Go で書くようになりました。(C言語/C++ は好きですよ)&lt;/p&gt;

&lt;p&gt;クセが強いからか、なかなか理解され辛いプログラミング言語でもありますが、本質的には実用的なアプリケーションを効率的に開発する事ができ、それでいてマルチコア CPU でスケールするといった、とても高いポテンシャルを持った言語だと思っています。日頃からこの高いポテンシャルを持ったプログラミング言語「Go 言語」をもっと皆に正しく理解して欲しい、もっと沢山使って欲しいと思っていたところに、技術評論社さんから本書の執筆のお話を頂きました。&lt;/p&gt;

&lt;p&gt;基本的な文法はほどほどに、並行処理の実装方法や、パフォーマンスを上げる為のテクニック、綺麗に書くための Tips、アプリケーションを順を追って解説混じりに実装する例、僕が Go で得た知識を沢山散りばめたつもりです。&lt;/p&gt;

&lt;p&gt;Go はC言語を良くしたプログラミング言語でもある事から、いくらかC言語を意識した記述がされています。しかしC言語を習得していない人達でもなるべく理解頂ける様に心掛けたつもりです。Go というプログラミング言語がスクリプト言語の様な書き味を持ち、それでいて高速なアプリケーションが実装でき、さらには並行処理を扱うアプリケーションを簡単に設計・実装できるという事を、本書でご理解頂けると信じています。&lt;/p&gt;

&lt;p&gt;ぜひ書店にて本書をお手に取ってご覧下さい。&lt;/p&gt;
</description>
     <author>mattn.jp@gmail.com (mattn)</author>
   </item>
   <item>
     <title>errors.Join が入った。</title>
     <pubDate>Sat, 01 Oct 2022 01:56:00 +0900</pubDate>
     <link>https://mattn.kaoriya.net/software/lang/go/20221001015441.htm</link>
     
     <guid isPermaLink="true">https://mattn.kaoriya.net/software/lang/go/20221001015441.htm</guid>
     <description>
&lt;blockquote class=&quot;quote&quot;&gt;
&lt;a href=&quot;https://github.com/golang/go/commit/4a0a2b33dfa3c99250efa222439f2c27d6780e4a&quot;&gt;errors, fmt: add support for wrapping multiple errors · golang/go@4a0a2b3 · GitHub&lt;/a&gt;
&lt;br /&gt;
&lt;p&gt;An error which implements an &quot;Unwrap() []error&quot; method wraps all the non-nil errors in the returned ...&lt;/p&gt;
&lt;cite&gt;https://github.com/golang/go/commit/4a0a2b33dfa3c99250efa222439f2c27d6780e4a&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go でエラーを扱う際に、複数のエラーを束ねたい事があります。例えば複数のタスクを実行し、1つでもエラーになれば中断するのではなく、一通りタスクを実施し終えた結果を返したい様なニーズです。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
&lt;span class=&quot;Statement&quot;&gt;package&lt;/span&gt;&amp;#160;main&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Statement&quot;&gt;import&lt;/span&gt;&amp;#160;(&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;errors&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;log&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;sync&amp;quot;&lt;/span&gt;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;&amp;#160;doMultiTasks(files []&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;)&amp;#160;&lt;span class=&quot;Type&quot;&gt;error&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;var&lt;/span&gt;&amp;#160;mu sync.Mutex&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;var&lt;/span&gt;&amp;#160;wg sync.WaitGroup&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;var&lt;/span&gt;&amp;#160;errs []&lt;span class=&quot;Type&quot;&gt;error&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt;&amp;#160;_, file :=&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;range&lt;/span&gt;&amp;#160;files {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;wg.Add(&lt;span class=&quot;Boolean&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;go&lt;/span&gt;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;(file&amp;#160;&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;) {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;defer&lt;/span&gt;&amp;#160;wg.Done()&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;f, err := os.Open(file)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;&amp;#160;err !=&amp;#160;&lt;span class=&quot;Boolean&quot;&gt;nil&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;mu.Lock()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;errs =&amp;#160;&lt;span class=&quot;Identifier&quot;&gt;append&lt;/span&gt;(errs, err)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;mu.Unlock()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;defer&lt;/span&gt;&amp;#160;f.Close()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Comment&quot;&gt;// do something&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}(file)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;wg.Wait()&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;return&lt;/span&gt;&amp;#160;errors.Join(errs...)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;&amp;#160;main() {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;err := doMultiTasks([]&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;{&lt;span class=&quot;String&quot;&gt;&amp;quot;not-found1&amp;quot;&lt;/span&gt;,&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;not-found2&amp;quot;&lt;/span&gt;})&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;&amp;#160;err !=&amp;#160;&lt;span class=&quot;Boolean&quot;&gt;nil&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;&amp;#160;errs, ok := err.(&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt;{ Unwrap() []&lt;span class=&quot;Type&quot;&gt;error&lt;/span&gt;&amp;#160;}); ok {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt;&amp;#160;_, e :=&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;range&lt;/span&gt;&amp;#160;errs.Unwrap() {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;log.Println(e)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;log.Println(err)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
}&lt;br /&gt;

&lt;/blockquote&gt;

&lt;p&gt;このコードは doMultiTasks に処理対象のファイル名を渡し、一通り実施した結果を返します。エラーを束ねるのに &lt;code&gt;errors.Join&lt;/code&gt; を使います。束ねたエラーは通常踊り error として扱えます。ただし束ねたエラーを戻す関数は現状用意されていませんが、error を複数返す Unwrap という関数で型アサーションしてやる事で複数のエラーに戻せます。&lt;/p&gt;

&lt;p&gt;また &lt;code&gt;fmt.Errorf&lt;/code&gt; を使い書式フォーマットに &lt;code&gt;%w&lt;/code&gt; を加える事でメッセージとエラーの両方を埋め込む事が出来ますが、本修正により複数の &lt;code&gt;%w&lt;/code&gt; を埋め込む事ができる様になりました。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
&lt;span class=&quot;Statement&quot;&gt;package&lt;/span&gt;&amp;#160;main&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Statement&quot;&gt;import&lt;/span&gt;&amp;#160;(&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;log&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;os&amp;quot;&lt;/span&gt;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;&amp;#160;main() {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;err := fmt.Errorf(&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;Special&quot;&gt;%w&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;#160;and&amp;#160;&lt;/span&gt;&lt;span class=&quot;Special&quot;&gt;%w&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;, os.ErrNotExist, os.ErrClosed)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;&amp;#160;err !=&amp;#160;&lt;span class=&quot;Boolean&quot;&gt;nil&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;&amp;#160;errs, ok := err.(&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt;{ Unwrap() []&lt;span class=&quot;Type&quot;&gt;error&lt;/span&gt;&amp;#160;}); ok {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt;&amp;#160;_, e :=&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;range&lt;/span&gt;&amp;#160;errs.Unwrap() {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;log.Println(e)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;log.Println(err)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;個人的にはそれほど多いニーズとは思っていませんが、無くはない程度に感じています。&lt;/p&gt;
</description>
     <author>mattn.jp@gmail.com (mattn)</author>
   </item>
   <item>
     <title>unsafe.StringData、unsafe.String、unsafe.SliceData が入った。</title>
     <pubDate>Wed, 07 Sep 2022 11:31:00 +0900</pubDate>
     <link>https://mattn.kaoriya.net/software/lang/go/20220907112622.htm</link>
     
     <guid isPermaLink="true">https://mattn.kaoriya.net/software/lang/go/20220907112622.htm</guid>
     <description>
&lt;p&gt;Go ではバイト列と文字列は異なる内部データとして扱っています。&lt;code&gt;[]byte&lt;/code&gt; から &lt;code&gt;string&lt;/code&gt; へ変換したり、またその逆を行う際にはキャストが必要になります。ですので string はイミュータブルになります。&lt;/p&gt;
&lt;p&gt;しかしイミュータブルなのは理解しつつもバイト列を文字列にする為に無駄なアロケートをしたくない場合もあります。これまで Go ではドキュメントに明文化していなかった為に色々な作法が生まれてしまっていました。その代表的な物が以下です。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
s := *(*&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;)(unsafe.Pointer(&amp;amp;b))&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;本来は、Go のバイト列の内部は &lt;code&gt;SliceHeader&lt;/code&gt; という構造体により管理されています。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;type&lt;/span&gt;&amp;#160;SliceHeader&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;struct&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;Data&amp;#160;&lt;span class=&quot;Type&quot;&gt;uintptr&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;Len&amp;#160;&amp;#160;&lt;span class=&quot;Type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;Cap&amp;#160;&amp;#160;&lt;span class=&quot;Type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;また string は以下の &lt;code&gt;StringHeader&lt;/code&gt; で管理されています。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;type&lt;/span&gt;&amp;#160;StringHeader&amp;#160;&lt;span class=&quot;Keyword&quot;&gt;struct&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;Data&amp;#160;&lt;span class=&quot;Type&quot;&gt;uintptr&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;Len&amp;#160;&amp;#160;&lt;span class=&quot;Type&quot;&gt;int&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;上記の unsafe.Pointer を使ったコードはこの struct の先頭2フィールドを無理やり参照する事で実現しています。実際に Go のコードでも使われており、これが公式の方法だと思って多くの人が使ってしまっていました。&lt;/p&gt;

&lt;blockquote class=&quot;quote&quot;&gt;
&lt;a href=&quot;https://github.com/golang/go/blob/3058d38632aea679c96cd41156b2751c97578a2d/src/strings/builder.go#L30&quot;&gt;go/builder.go at 3058d38632aea679c96cd41156b2751c97578a2d · golang/go · GitHub&lt;/a&gt;
&lt;br /&gt;
&lt;cite&gt;https://github.com/golang/go/blob/3058d38632aea679c96cd41156b2751c97578a2d/src/strings/builder.go#L30&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;blockquote class=&quot;quote&quot;&gt;
&lt;a href=&quot;https://github.com/search?l=Go&amp;q=reflect.StringHeader&amp;type=Code&quot;&gt;Sign in to GitHub · GitHub&lt;/a&gt;
&lt;br /&gt;
&lt;cite&gt;https://github.com/search?l=Go&amp;q=reflect.StringHeader&amp;type=Code&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;blockquote class=&quot;quote&quot;&gt;
&lt;a href=&quot;https://github.com/search?l=Go&amp;q=reflect.SliceHeader&amp;type=Code&quot;&gt;Sign in to GitHub · GitHub&lt;/a&gt;
&lt;br /&gt;
&lt;cite&gt;https://github.com/search?l=Go&amp;q=reflect.SliceHeader&amp;type=Code&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;p&gt;しかしながらこの実装は、今後 Go の文字列とバイト列に関する最適化の妨げになり得ます。例えば StringHeader と SliceHeader の交換を最適化する事ができなくなります。&lt;/p&gt;

&lt;p&gt;そこで今回、unsafe.StringData、unsafe.String、unsafe.SliceData が入りました。これによりバイト列から文字列、またはその逆がミュータブルに変換できる様になりました。当然ですがこれらはバイト列の破壊的な変更により意図しない文字列の変更が行われる為、慎重に取り扱わなければなりません。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;&amp;#160;StringToBytes(s&amp;#160;&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;) []&lt;span class=&quot;Type&quot;&gt;byte&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;return&lt;/span&gt;&amp;#160;unsafe.Slice(unsafe.StringData(s),&amp;#160;&lt;span class=&quot;Identifier&quot;&gt;len&lt;/span&gt;(s))&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Keyword&quot;&gt;func&lt;/span&gt;&amp;#160;BytesToString(b []&lt;span class=&quot;Type&quot;&gt;byte&lt;/span&gt;)&amp;#160;&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span class=&quot;Statement&quot;&gt;return&lt;/span&gt;&amp;#160;unsafe.String(&amp;amp;b[&lt;span class=&quot;Boolean&quot;&gt;0&lt;/span&gt;],&amp;#160;&lt;span class=&quot;Identifier&quot;&gt;len&lt;/span&gt;(b))&lt;br /&gt;
}&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;unsafe.StringData は string が持っているバイト列へのポインタが返されます。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
fmt.Println(unsafe.StringData(&lt;span class=&quot;String&quot;&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;))&lt;br /&gt;
fmt.Println(unsafe.StringData(&lt;span class=&quot;String&quot;&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;))&lt;br /&gt;
fmt.Println(unsafe.StringData(&lt;span class=&quot;String&quot;&gt;&amp;quot;Hello1&amp;quot;&lt;/span&gt;))&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;これを実行すると以下の様に表示され、Go のコンパイラが文字列リテラル Hello の2つをまとめて保持しているのが分かります。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
0xc67760&lt;br /&gt;
0xc67760&lt;br /&gt;
0xc6790b&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;また文字列がスタックに取られている時にはメモリ破壊が発生しますのでランタイムでクラッシュします。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
s :=&amp;#160;&lt;span class=&quot;String&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;br /&gt;
b := StringToBytes(s)&lt;br /&gt;
b[&lt;span class=&quot;Boolean&quot;&gt;0&lt;/span&gt;] =&amp;#160;&lt;span class=&quot;Constant&quot;&gt;&apos;h&apos;&lt;/span&gt;&lt;br /&gt;
fmt.Println(s)&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;以下の様にヒープにメモリが確保されている場合には期待通りに動作します。&lt;/p&gt;

&lt;blockquote class=&quot;code&quot;&gt;
s :=&amp;#160;&lt;span class=&quot;Type&quot;&gt;string&lt;/span&gt;([]&lt;span class=&quot;Type&quot;&gt;byte&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;))&lt;br /&gt;
b := StringToBytes(s)&lt;br /&gt;
b[&lt;span class=&quot;Boolean&quot;&gt;0&lt;/span&gt;] =&amp;#160;&lt;span class=&quot;Constant&quot;&gt;&apos;h&apos;&lt;/span&gt;&lt;br /&gt;
fmt.Println(s)&lt;br /&gt;
&lt;/blockquote&gt;

&lt;p&gt;動的なアロケーションが発生しないため高速な変換が可能です。おそらく今後、Go の内部実装の多くがこれらで置き換わっていき、幾らか高速化が見込まれます。&lt;/p&gt;
</description>
     <author>mattn.jp@gmail.com (mattn)</author>
   </item>
  </channel>
</rss>
