Go language part 5
Goがpromise(future)/async/awaitをサポートしてくれれば今より容易に安全に書けるケースが増えるのは事実だが、
この件も他の件と同様にGoはサポートしてくれないだろうという悲観的な現実と向き合って、
今ある手段で頑張って代替手段を安全に実現しよう。 結局ゴルーチンの実装が中途半端だったんだろうね
分散環境でのストリームモデルならNodeみたいなノンブロッキングIOで外部のソケットを叩けるようにして
シングルスレッドにするのが良かったし
そうでないならFuture/Promiseみたいに安全にデータを受け取れる仕組みが欲しかった
この2つがちょうどうまくできないデザインになっちゃった またGoの言語仕様にも問題があった
ジェネリクスだ
ジェネリクスがない状態でfuture/promiseを安全に実装できない
なぜかアンチジェネリクス勢がGoには多く
コミュニティでの議論も進展しなかった
つまり全てがゴテゴテに回ってしまった
それならGoogleが並行処理のフレームワークを作ってくれるのかと期待していたが
その気配は全くなく使いにくいcontextのみを放り投げた状態でさあ作れと言った状態
そりゃ普通のユーザーは付いてこれない マルチコアを効率よく使うってのがそもそもコンセプトで作られたんだがNodeみたいにしろって意味わからん Goのようにマルチコアを効率よくスケジューリングできて
Goのgoroutineのように多数のタスクを身軽に簡単に起動できて
Goのようにそれらタスク間でchannel通信をすることができて
それらに加えてFuture / async / awaitもサポートしているプログラミング言語がありますよ
偶然ですがその言語は
Goと同じくclassや継承がなく
Goと同じく例外try-throw-catchもなし >>558
まずpromiseがどう有利なのか自分の口からどうぞ
そこにメリットを見いだせないから無視されるんだよ Goのモデルと比較してのpromiseの優位点としてはこんなとこかな
・一般に、並行性が多少犠牲になる代わりに並行処理の複雑性を局所化する方向へとデザインが誘導される傾向がある。結果としてバグが入り込みにくい。
・ワークフローを集約して記述しやすいため可読性保守性に優れる。
・(channelではなく共有メモリを使う場合と比較して)処理結果を他のスレッドで利用する際にデータ競合が生じない。
・channelと比較して、結果として単一の値を生成するというセマンティクスが型として明確に表現される。デッドロックや閉じ忘れの心配もない。 うーん今の時代にpromiseの利点を理解できない人がいるとは驚きですが仕方ない出血大サービスだ
まず最初にマルチコアを活かすという点についてだが
基本的にゴールチンのような仕組みでは全く活かせないという点を強調しておく
まともにマルチコアのCPUの性能を引き出せるのはSIMD命令を使った計算のみ
SIMDが何なのかわからない人は調べてください
SIMD演算を直接言語でサポートしていないので計算の高速化は論外
ただのマルチスレッドと変わらない
マルチスレッドはOSレベルで実装されており
コンテキストスイッチの負荷も高くCPUキャッシュも消えるし
マルチコアを活かすような作りになってないのはご存知の通り >>562
嘘ついちゃだめ
promiseでもデッドロック起きる 次にpromiseの利点について
並行処理の考え方としては大きく以下がある
1.処理をシーケンシャル実行して1つずつ結果を受け取る
Aが終わったらBを実行して
Bが終わったらCを実行する
2.複数の処理を同時に実行して結果をまとめて受け取る
A、B、C...の処理を同時に実行してその結果をreduceして受け取る
3.ストリーミングモデル
いわゆるproducer/consumerに代表されるようなモデル
1と2についてはpromiseで全て安全に楽に実装できる
ゴルーチンとchannelを使った実装なんか考えたくもない
100%デッドロックが起きる
3についてはゴルーチンとchannelが本来想定してるモデルなのだが
これを適切に実装するのが難しい
CでBlockingQueueの実装したことがある人は分かると思うが極めてデッドロックが起きやすい
複数のproduer/consumerを生成したい場合など考えたくもない
さらにこのモデルの場合は基本的に大規模な分散環境で実行することがほとんどである
シングルノードでproducer/consumerなどサンプルコードでしか有り得ない
こういう用途では複数ノードのソケットにリクエストを投げて結果を待つということになるので結局2に帰着される つまりpromiseがあれば全ては安全に解決される
ちなみにpromiseはスレッド実装する必要はないことに注意
rustはスレッドで実装されているがNodeはノンブロッキングIOを使っている
他にもグリーンスレッドを使うなどいろいろある
言語側が安全性を担保できるように実装できるのだ
そしてpromiseを型安全に実装するためにはジェネリクスは必須である
以上が私の考える
「ゴルーチンは実装が中途半端で実際のユースケースを考えた場合に非常に残念なことになっている」理由である
反論があればどうぞ そりゃpromiseでも共有メモリ触ったり外部のリソースをロックしようとしたりすればデッドロックするでしょう
promiseモデルとは関係ない話 >>560
その言語はRustだな
>>565
Rustならデータ競合が絶対に起こらない
データ競合を起こすコードはコンパイラがエラーにできる言語仕様
>>567
ちょっと違う
RustのFuture(=Promise相当)はOSスレッドとは全く別で関係なく
Goroutineとほぼ同様の気軽に大量に作れる非同期タスクとして扱える
もちろん安全に解決できる
今回の話で言えば大雑把に分けるとRustは3種類ともサポート
① Futureおよびそのasync/await
➁ Goと同様のchanel
③ メモリ競合を絶対に起こさない安全な共有メモリ ぐちぐち言ってきたが
Goにはゴルーチンとchannelとcontextという良いプリミティブがあるのだから
適切にpromiseを実装して使えるようにして欲しいということ
であれば並行処理がメインのアプリにおいては第一選択にもなり得ると思う
ジェネリクスも入ったのだしやれるはずなんだよ
Googleがもうやる気ないのかもしれないけど >>568
channelと比較してデッドロック起きないとか痛い事言っといてそれはないわw Nodeしかさわったことないから詳しくは知らんけどasyncawaitモデルだと
async関数を使うには呼び出し元にどんどんasyncが汚染されて使いづらいイメージがあるな
その点Goは同期的なコードの一部を並行処理にするってのが非常にやりやすいと思う
タイムアウト処理もselectで簡単に実装できるし、シンプルなfork joinだったらsync.waitgroupで楽に実装できるし
何も困ったことがないな
そんなに優位性があるとは全然思わない >>573
Goは見かけ同期と誤認するけど
同じOSスレッド上でもメインや複数のGoルーチンがスケジューリングされて交互に非同期で動いているよ
例えばGoで
func1()
func2()
func3()
と見かけ同期に書いているのは
async/await対応言語で
await asyncfunc1()
await asyncfunc2()
await asyncfunc3()
と書いた時と同じ状態
つまり見かけ同期のGoの実態は非同期
「Goは最初から全てがasync汚染されているためasync汚染に気付かずに済む」が正解 >>574
goキーワードなかったら同期的に動くだろ
ライブラリの中でgoキーワードが使われてるから暗黙的に使われるが正しいね。
非同期にしたい部分でgoをつけるのであってつけてないのに全部非同期だってのはおかしな話だな >>575
それは見かけ上だけ
goを付けなくても読み書きなど含めて時間がかかるものは
見かけ上だけ同期ブロックしているが
実際には非同期で動いており裏で別のgoroutineにスケジューリングされている
そしてその読み込みや書き込みが可能となると
見かけ上だけ同期ブロックしていたところへスケジューリングが戻る仕組みであってGoは常に非同期に動いている ユーザーに見せてるのは全てブロッキングなコードなわけじゃん
それをgoキーワード使って複数立てた時に非同期で動くって話で、単体の場合はあくまでも同期的に動くよね
mainルーチンでhttp.getってやったら同期的に動いてるよね?
これを別のgoroutineを立てて複数立ち上げればブロックする後は勝手に非同期で動くってだけの話
async汚染はユーザー目線で言ってるね
Goのモデルは既存のコードや構造に手を加えずに一部だけを非同期にするのが容易、これが一つのメリットではあると思う Node/Denoの作者も同じこと言ってるし、async/awaitモデルの方が優れている一言も言ってないな
むしろGoのモデルをほめてるわ
https://mappingthejourney.com/single-post/2017/08/31/episode-8-interview-with-ryan-dahl-creator-of-nodejs/
必死にasync/awaitの方が優れてるとか言ってるみたいだけど、逆にGoのモデルの方が使いやすいって人もいるわけだよ
自分の意見が全てだと思わない方がいいんじゃないかな
感覚的な話で優れてるって言われてもね >>577
> ユーザーに見せてるのは全てブロッキングなコードなわけじゃん
それは見かけだけだな
例えば>>574の
| await asyncfunc1()
| await asyncfunc2()
| await asyncfunc3()
これも(同じく見かけだけ)全てブロッキングな同期で実行されるコード
そしてGoと同様に実際には裏で非同期に動く
> 単体の場合はあくまでも同期的に動くよね
それは見かけだけ
つまりasync/await対応言語がawait文で見かけだけ同期的に動いているように見せかけるのと完全に同じ うんだからユーザーに見せるコードが同期的なことろがわかりやすくて良いって言ってるんだけど?最初その話してたよね?同期的なコードって言ってるよ?
裏でepollやら使ってて非同期だから云々の話はしてないんで
ちなみになんでいちいちID変えるの? >>576
>見かけ上だけ同期ブロックしているが
>実際には非同期で動いており裏で
んなこと言ったらIO操作のあるあらゆる言語が低レベルでは非同期で動いてるじゃんよ。 C10K問題から非同期が流行ったのに、メモリーを使いまわしてたら意味ないのでは?
一つのスレッドに一つのスタック、典型的に一つのスタックは1MB準備される。
10Kのスレッドがあれば、10GBのメモリーが必要。
256MBのSUNでは無理。
でも、非同期でも1MBの配列を用意してデータが届くたびに書き足していくなら同じことでは? ウェブ・サーバーが静的なファイルを送り出していた2000年ごろなら非同期が大それた力だっただろうけど。
全てが動的な現代において、非同期はめんどくさいだけなのでは? 昔より回線が安価になって接続数が多くなったんだから非同期が必要でしょ 静的なファイルを送るだけなら。
カーネルの送信バッファが空くのを待つ
↓
送信バッファと同容量だけ非同期にファイルの読み込みを開始する
↓
ファイルデータが読み込まれると、送信を開始する
↓
最初に戻る
この手順で、典型的なTCP通信なら20KB以下のメモリーで足りる。
でも、動的なコンテンツ生成では、そうはいかないのでは? >>563 のここがよく分からない
> まともにマルチコアのCPUの性能を引き出せるのはSIMD命令を使った計算のみ
SIMD命令付きのシングルコアCPUもあったじゃん。
古いけど MMX Pentium とか Pentium III とか。
この時代はSIMD命令は何を引き出してたの? >>566
1なんか一つのgoroutineに上から並べるだけで良いじゃん。 えっ?もしかしてこの人
>>574
でもまだ理解してないの? >>587
httpを同期で実装するなんて昔のダメなシステムと完全ブロックしても困らない末端クライアントだけたぞ
httpクライアントとして動作する時もサーバーで使うなら同期ブロックしてしまうとスレッド資源を無駄に専有
だからhttpを使うなら何らかの非同期にするのが当たり前 >>574
多くの言語でasync/awaitキーワードだらけになって反吐が出る気分だわ、これを良いと考えた人たちを殴りたい...
goにpromise/futureなんて絶対不要、こんなの必要だと思ってる人相当アホやぞ
>「Goは最初から全てがasync汚染されているためasync汚染に気付かずに済む」が正解
なるほど意味わからん
asyncキーワードなんて無いのにスケジューリングで同期実行されるから汚染?ww新理論w >>566
1なんてそのまま関数並べるだけだし
2はN件goroutine立ち上げてたらN回チャネル待ち受ければいいだけだよね
タイムアウトもselectで容易に実装できる
100%デッドロックするとか言ってるけどそれはGo超初学者が使った時の話かな?
仮にデッドロックしても検知機構働いてちゃんと落ちるし何が言いたいのか >>588
その時代のことはよく知らないので
気になって調べてみたがwikipediaによると
2クロックで実行するという実装になっていた模様
なのでその時代に関しては128ビット幅のレジスタを使えるというアドバンテージしかなかったとのこと >>591
通信プロトコルとhttpサーバー/クライアントの実装が区別できないおバカさん乙w
そんなんでよくGoなんて使えるな 今回は実装の話だからサーバー上なら今どきは非同期で実装で合ってると思うよ >>593
その通りだな、安易に実装できるものを標準で欲しがる理論がわからんわ
多くの言語のfutureなんてデータの結果受信同期待ちが起こるだけだし、goのcontext.WithTimeoutは
他の言語では全く実装できていないfutureのプラス機能のようなもので、goはより進んでいると言える
一方promise的なもの、つまり複数のgoroutineを束ねて制御したい人は、欲しい人もいるかもしれないが
goで書いたpipeline処理は手動で書くからこそきめ細かい制御が出来るので、無作為にこれとこれを並列、
これとこれを非同期だけど同期的に実行にしたいとか、効率を考えたらこの流れを組み替えられることには
ほとんど意味もないね。
例えばJSでPromise.allとかすべてを非同期並列に実行して成功の可否で分岐したいなんて、同じ状態が
goroutineとチャネル待ち受けで出来てしまうわけで、それを仰々しいライブラリにする意味が分からん 上では良いことだけ書いたけどif err != nullはもうそろそろダルいので何とか手を打ってほしいわ
副作用のある関数ではgoの第二の戻り値がerrなのは、もはや言語仕様なので別言語でいう
Option/Result/Eitherみたいなものは必要ないにしても、?.のようなNull条件演算、合体演算
のようなErr条件演算が欲しい きめ細かい制御してるか?
goのモデルは良くも悪くも作った水路に水を流すだけで、実際にその中のどこでどのようにブロッキングが発生するかは気にしないのが正しい使い方
どっちかというとpromise系のほうが制御は明示的だよ きめ細かいGoのpipelineって、もしかしてGoあんまり書けないのでは…?
ランタイムの大勝利な事の方が多いぞ。 きめ細かいでしょう?
チャネルが1個なら並列性が1つでブロッキング出来るし、並列性を持たせたいなら複数のチャネル幅を
用意すればいいだけ1段目のパイプライン処理が終わったすぐ後に、次段のパイプライン処理を普通に書く
ことができるし、sync.WaitGroupを使えばパイプライン中の中間データへ同期制御もできる
それ以外にGoで書かれた多くの優れたパイプライン処理は、キャンセルを考慮している。
ブロッキングが発生するかは気にしないなんて事はなく、チャネルのselectでブロッキングが入ることは普通に
当たり前だから気にしないだけ
https://go.dev/blog/pipelines
世にある多くのpromiseはキャンセルやタイムアウトは考慮していない場合が多い、All or Nothingでしかない
大雑把な実行制御でしかない。多くは流れるようなデータの受け渡しもできない。
実行順を決めるだけで、特定の処理に多重度を持たせるとかそんなことは出来ない
これは多くがpromiseというものが非同期処理をベースにした疑似的な実行順制御の仕組みだけであるから >>598
そもそも、複数のgoroutineを束ねて使いたいという要請でsync.WaitGroupは作られてるから、自前で作る意義すら無いんだよな
グループを待つ、のだから >>593
だからその程度のことしかしないのにわざわざゴルーチンだのchannelだのselectだのを書かなきゃいけないことがだるいと言う話だよ?
書けるか書けないかで言ったらそりゃ書けるでしょw
あと普通に刺さる可能性が高いと言うことを言ってる 意味わかんね
>>566 では promise の利点をこう書いてた
> 1と2についてはpromiseで全て安全に楽に実装できる
> ゴルーチンとchannelを使った実装なんか考えたくもない
> 100%デッドロックが起きる
それに対して >>593 や >>598 が goroutine とチャネルで簡単に実装できるって言ったら >>605
> わざわざゴルーチンだのchannelだのselectだのを書かなきゃいけないことがだるいと言う話だよ?
「だるい」なんて話、一切してなかっただろ。 >>607
マジでアスペか?
promiseの方が明らかに楽でバグが生まれない
これはこれまでの議論の流れで一貫してる主張
なんでリクエストのデータ受け取るのにgoルーチンだのchannelだのselectだの書かなきゃならんのだよ
そしてpromiseを実装するのは我々ではなくGoコンパイラの開発者たちだよ promiseって普通awaitするのが普通だよね?
goもチャネルも使わない状態でhttp.Get呼ぶのと全く同じだよ
goroutineの中で実行すれば勝手に非同期になるしfork joinしたいならチャネルがwaitgroup使うだけの簡単なお仕事 >>608 >>607
まずは「goroutine&channelだと100%デッドロックが発生してpromiseだと発生しない状況」について戦えよ。
だるいとかより興味あるわ。 >>608
「promiseの方が明らかに楽でバグが生まれない」
そんな統計は1つもないければ、あなたの貧相な頭の中だけですよね?それを証明しなさいと暗黙的に問われているのがわかりませんか?
「なんでリクエストのデータ受け取るのにgoルーチンだのchannelだのselectだの書かなきゃならんのだよ」
じゃあなんで、promiseなんていう出来の悪い非同期処理のために作り出された愚物を、真にマルチプロセスに対応するgoで
エミュレーションしなきゃならないんですか?あなたのためだけですよね、ほとんど誰も欲しがっていませんけど?
このような需要がない機能を、標準ライブラリに求めるものではありませんし、あなたの隠れた真の心は
「学ぶことをしたくない」だけでしょう、ご自分でも気づいてないと思いますが
C#やScalaあるいはJSしか出来ないなら素直にチームに報告しましょう、あなたのやる気を引き出すためだけに我儘を際限なく
広げても誰も理解してくれませんし、当然、味方にもなってくれないでしょう。だってやる気が無いんですから。
言語の基本的な考えが違うのに、他の言語に似たような雰囲気を求めるのは間違っていますし、なおかつ結局同じコードを
書いてしまうなら乗り換えるような利点をすべて消し去るでしょう
「そしてpromiseを実装するのは我々ではなくGoコンパイラの開発者たちだよ 」
実装しないと思いますね、あなたのゆがんだ考えでは超保守的なgoチームを説得するのは無理でしょう。1つも有益な
調査結果なり、推測なりが述べられていません。あなたが「ルーチンだのchannelだのselectだの書かなくちゃならない」と
我儘を言ってるようにしか見えません。仮に万が一億が一、必要だとしてもGithubに個人実装のライブラリとしてあるでしょう まあasync/awaitのほうが初心者に対するハードルは低そうな気はする
初心者が雑にchannel使ってるとたいていバグってるわ async/await手軽で簡単だけど複雑なことやろうとすると難しい
Goroutineとchannelはasync/awaitと比べると確かにとっつきにくいが複雑のことも組み合わせで上手く実現できる応用力がある >>611
そういうストローマン論法は俺には通用しないって promise の利点まとめ
- goroutineとchannelを使うと100%デッドロックが起きるが promise だと安全に実装できるものがあるらしい。具体例は不明。
- >>605 にとってだるくない。 非同期で順列な処理やる場合はasyncのがわかりやすい
並列にタスクいっぱい撒いてなんかやるみたいなのはchannelって印象 promiseに似てるけど、全く違うものはerrgroup.Groupと呼ばれます。これもpromiseなんぞと比べれば
コンテキストなどと組み合わせキャンセルやタイムアウト処理が容易にできますし、実行順の制御や包括した
エラー処理以外にパイプラインまで簡単に拡張できます。
例1:ページをフェッチして全ての処理が終わるまで待つグループ制御(1つでもエラーならエラー処理)
https://pkg.go.dev/golang.org/x/sync/errgroup#example-Group-JustErrors
例2:単純な並列タスクを同期するためのグループ制御
https://pkg.go.dev/golang.org/x/sync/errgroup#example-Group-Parallel
例3:多段ステージを設けたパイプライン処理をグループ制御
https://pkg.go.dev/golang.org/x/sync/errgroup#example-Group-Pipeline
例1、例2はJSでいうPromise.all() のような動きをしますがpromiseなんていう融通の利かない非同期のため
だけの劣った機能より格段にシンプルな仕組みです。
上の例でいえば、並列タスクなどではchannelを使用せず、複数起動された軽量ルーチェンから元ルーチェンへ
results配列の結果を戻していますが、これは並列タスクが一段で終わるからです。
次の(例3の)pipeline処理にあるように、並列と並列が連鎖する多段処理においてはchannelのような
仕組みを使うのがとても合理的です。もちろん、処理の終わりの同期のために、selectによる結果受信待ちは
入りますがこれはデットロックではありません
もともとJSのPromiseがなぜあるかといえば、同じプロセス空間で疑似的な非同期処理による実行制御を行うため
だけの仕組みです。このため、特定の変数(結果を格納する配列や変数)に同時にアクセスされるという考えは
ありませんし、そのような(ロックや待ち)制御は必要ありません。現実に同時に動いていないのですから
隣国のアジア人コミュニティに「ストローマン論法」という言葉を連呼するキチガイ集団がいましたが、本当のバカだった 結局何がChannelに無くて、何がPromiseでしか解決できない問題なの?
Promiseを解決せずに持ち回ること? >>617
例1がすでに全然シンプルじゃないw
しかもレスポンスを返さない例で意味ないww
それ以外にも落とし穴満載
現実にこんなコード書いてるやつばっかりならバグりまくってヤバそう やはり頭がバカ以前のGより脳が小さい、上の人はサンプルをシンプルだとは上でも言ってないが
errgroup.Groupがシンプルだと言っているのに、頭ヤバそう
まあサンプルは十分シンプルだが、レスポンスが要らない事など世の中にいっぱいある
現実にこんな奴がいることは、goより複雑な言語特性や膨大な標準ライブラリを持つ言語を
チーム開発で使えるか、大変考慮すべきことだろうな まずは基本的に、シングルスレッドの場合とマルチスレッドだが共有データを使用しない場合は原理的に
データ競合や排他制御のバグは発生しない。
>>611が「promiseの方が明らかに楽でバグが生まれない」と言っているのはそのどちらかに帰着するケース。
マルチスレッドでかつ共有データを扱うケースではpromiseを使おうが競合バグは発生し得る。 ストローマン連呼する人が最近5chで増えたと思ったけどこの動画が原因なのねん
youtu.be/mK3Tnxh4Kho そもそもGoは何もしなくてもマルチスレッドなんよ。
IO待ちとかしたら勝手に他の事しよるよ。awaitなんかしなくても。
だからFutureやPromiseで結果が来る事を持って回るんじゃなくて、
そもそも処理するロジック自体を複数起こしちゃうんだよ。。
これだけの事をいつまで言ってんのよ。。
>>617
の例1がどうして一気に複数リクエストを送りたいかと言うと、その三つを同じ一つの処理で使いたいからであって、
三つの同じ処理を起こすんであればWaitする必要も無いのでは?
それこそchanで受け取れば良いんだし。。 JSのPromiseしか知らないんだな
そりゃ話が噛み合うわけがない 内容ゼロのワイ賢者や煽りに煽りで返すスタイルwww ストローマンって本題から離れた部分を、わざと誤解して上げつらう詭弁の手法だから、自己紹介してるんだよ うぬぬぬぬ、issueに送るべきだろうか?
1、「ポインタの」レシーバーでストリンガーを記述すると、fmt.Println()とかに渡してもString()メソッドは呼んでくれない…
2、そして(str{v: 1}).String()とか記述するとコンパイルエラーになる…
変数に一旦格納してからのs.String()は、仕様から(&s).String()と解釈してくれて通る >>634
この辺(レシーバー)の仕様って、訳してみると何かガバッてるように思えてならないんだよなぁ >>634
実体のレシーバーはレシーバー内のフィールドを更新しても反映されないから、レシーバーはポインターとして書くのが定石だけど
ストリンガーだけ実体のレシーバーとして書けば回避できる
回避できるなら放置でもいーじゃん?とか言われると反論しづらい >>638
ポインタのレシーバーを記述していると、インタフェース型変数には実体は代入できずポインタでなければならない
という制限もイミフ
代入可能性の仕様は単に、xがインタフェースTを実装していること
実体でもメソッドセットx.String()とx.Str()は呼び出せるのだから実装されている、とは「ならない」事から上記の制限がイミフと言ってる
本当に仕様が厳密じゃなくてガバガバ
大真面目に仕様書を読み込んでる俺の純情を返せ >>639
セレクタ式で実体からポインタレシーバーを呼び出すと&xと解釈されるという仕様が、インタフェースの代入可能性には波及していない、という点でコンパイラのバグと難癖つけられるんじゃないか?
とissueに書いてもいいんじゃないか?という多分にメンドクサイ系おじさんの怒り
仕様書にどう書かれていようが、インタフェースに実体を入れようとするな!で済む話ではあるかも
最終的には「仕様書は信用するな」に帰着 インターフェース型変数という訳のわからないものを導入したのがそもそもの間違いなんだよな で、なんでそんなもんを導入したかというとそもそもジェネリックスがなかったから
「ジェネリクスがなくてもプログラムは書ける(キリッ」みたいなイキりにこだわって結局かえって醜いことになるっていうまるでド素人みたいな失敗 理解できないから人格攻撃に出るあたり、お里(国)が知れるというもの いきなり国がどうとか言い出す人って日常会話出来るのか気になる インタフェース変数は普通に色々な言語にあるだろ?
そこにケチをつけるのは筋が悪すぎるのではないか? >>636
1. &elem2{}で渡してるのに、func (e elem2) String() stringなんて呼び出すわけないじゃん?どういう事?
2. func (s *str) String() string で普通は定義するので、同じように呼べないからコンパイルエラー
もっと言えば、s := str{}にしても (*str).String(&s)とコンパイル時に解釈されるだけで呼んでるのはポインタメソッド
下のインタフェース型変数云いいは、全く理解ができていないで我儘いってるだけで読んでる人に伝わってないし
マジ何が言いたいのかサッパリ...
goの仕様ほど厳格なものはないと思うけど(比べるのはC/C++や2015年代以前の言語ね、2016年以降の言語と
比べても、いまだに詳細なメモリレイアウトさえ公表できない某錆より厳格だ)本当に大真面目に読んでる?
golangを始める必要性に駆られて、こんな簡単な入門初めのプログラムでケチ付けたいだけじゃ?
issue書いても良いけど、保守的なgolangメンテナーに絶対相手にされないよ >>648
ちゃんとコードを読みなよ
elemはポインタレシーバーで実装、elem2は実体レシーバーで実装
そしてポインタレシーバーでストリンガーを書くと、fmtパッケージとかでは認識されないケースがあるってサンプルコードよこれ
つまりあなたの主張する func (e *elem)String() string という「普通の定義」では動かないケースを示している
実行してみ?俺も「普通の定義」だと思っていたからこそのレスなんだから func (e *elem) String() string
と書くとストリンガーとして認識してくれないと説明して
サンプルコードまで載せて確認を求めてるのに
実行すらしてもらえないとは 仕様書にポインタ変数.は勝手に*(ポインタ変数).
に変換されるとか書いてあるけどインターフェースでも行われるってのはどこに書いてあるの? >>651
ない
むしろ、インタフェースを実装しているという定義が、全てのメソッドセットを満足している、という程度しか書かれていない
あれ?仕様書だと逆に値は (&x).xxxx に変換されるとしか書かれてなくなかったか?後で確認してみる ポインタと値レシーバーは特に注意しなくても相互にセレクタとして呼べるんで気にしていなかったんだけど、ポインタでストリンガーを書いたらfmtパッケージの関数では認識してくれなかった
んで、これは不味いと総当たりで確認してみた
しかし、単に自分の勘違いかなと確認コードを公開してみて、レビューを求めている←イマココ まだfmtパッケージの中は見ていないけど、ポインタレシーバーで書くと型スイッチかリフレクションではインタフェースを満たしていないと見なされたりするんじゃないか?とか不安になってきた
上でも書いたけどfunc (e *elem)String()は自分も「普通の」書き方だと思ってたんで な、仕様なんてこいつ読んでないだろ?5chぐらいでしか自分の連投でしか意見言えない
issueとかこいつは言ってみただけでそれすら出来ない >>655
そいつ次世代言語スレで機能精神崩壊してたんだぜ
自分のRustの実力(知ったか)で仕事にありつくのが難しいと観念して これからはGoに粘着するよ
ここが新しい 隔離スレ よろしく頼む