私はGAE用のアプリを書くことでGoを学んでいます。これは、ハンドラー関数のシグネチャです。
func handle(w http.ResponseWriter, r *http.Request) {}
私はここではポインタ初心者ですが、なぜRequest
オブジェクトはポインタなのResponseWriter
ですか?このようにする必要はありますか、それともある種の高度なポインタベースのコードを可能にするためだけですか?
私はGAE用のアプリを書くことでGoを学んでいます。これは、ハンドラー関数のシグネチャです。
func handle(w http.ResponseWriter, r *http.Request) {}
私はここではポインタ初心者ですが、なぜRequest
オブジェクトはポインタなのResponseWriter
ですか?このようにする必要はありますか、それともある種の高度なポインタベースのコードを可能にするためだけですか?
回答:
何を取得することはw
非エクスポート型へのポインタでhttp.response
はなくとしてResponseWriter
表示されていないインタフェースが、あります。
server.goから:
type ResponseWriter interface {
...
}
一方、r
は具象構造体へのポインタであるため、参照を明示的に渡す必要があります。
request.goから:
type Request struct {
...
}
http.ResponseWriter
インタフェースであり、このインタフェースを実装し、既存のタイプがポインタです。つまり、このインターフェイスはすでにポインタによって「バックアップ」されているため、このインターフェイスへのポインタを使用する必要はありません。この概念は、ここでgo開発者の1人によって少し説明されています。http.ResponseWriterを実装する型はポインターである必要はありませんが、少なくともgohttpサーバー内では実用的ではありません。
http.Request
はインターフェースではなく、単なる構造体です。この構造体を変更してWebサーバーにそれらの変更を認識させたいので、ポインターである必要があります。構造体の値だけの場合は、コードを呼び出すWebサーバーが認識できないコピーを変更するだけです。
ここや他の場所で他の多くの回答で正しく言及されているようにResponseWriter
、インターフェースであり、これの意味はSOの回答とブログで詳細に説明されています。
私が対処したいのは、ここでの大きな、そして危険な誤解であると感じていることです。リクエストが「参照」によって渡される理由は(Goには実際には存在しませんが)、「変更を加えたい」ということです。サーバーに表示されます」。
いくつかの答えを引用します:
[..]これは単なる構造体であり、この構造体を変更してWebサーバーにそれらの変更を認識させたいので、ポインターである必要があります[..] SO
[..]ハンドラーによるRequestへの変更はサーバーに表示される必要があるため、値ではなく参照によってのみ渡します[..] SO
これは間違っています; 実際、ドキュメントはリクエストの改ざん/変更に対して明示的に警告しています:
本文を読み取る場合を除いて、ハンドラーは提供されたリクエストを変更しないでください。
まったく逆ですよね?:-)
ミドルウェアチェーン内の次のハンドラーに渡す前にトレースヘッダーを追加するなど、リクエストを変更する場合は、リクエストをコピーして、コピーしたバージョンをチェーンに渡す必要があります。
着信リクエストの変更を許可するように動作を変更するリクエストがGoチームで提起されましたが、このような変更を行うと、少なくとも一部の既存のコードが予期せず破損する可能性があります。
リクエストを変更しないように明示的に指示しているのに、なぜポインタを使用するのですか?パフォーマンスは、Request
大規模な構造体であり、それは特に念頭に置いて、長いミドルウェア鎖で、パフォーマンスをダウンさせることができますコピーします。チームはバランスをとる必要がありましたが、これは間違いなく理想的なソリューションではありませんが、トレードオフは明らかにここでのパフォーマンスの側面にあります(APIの安全性ではありません)。
それがRequestへのポインターである理由は単純です。ハンドラーによるRequestへの変更はサーバーに表示される必要があるため、値ではなく参照によってのみ渡します。
net / httpライブラリコードを掘り下げると、ResponseWriterはエクスポートされていない構造体応答へのインターフェイスであり、値ではなく参照によって構造体を渡していることがわかります(応答へのポインタを渡します)。 。ResponseWriterは、ハンドラーがHTTP応答を作成するために使用するインターフェースです。ResponseWriterをバックアップする実際の構造体は、エクスポートされていない構造体http.responseです。エクスポートされていないため、直接使用することはできません。ResponseWriterインターフェースを介してのみ使用できます。
つまり、両方のパラメーターが参照によって渡されます。メソッドシグネチャが構造体へのポインタへのインターフェイスであるResponseWriterを受け取るだけなので、値によって渡されたかのように見えます。