Trong các trình xử lý HTTP Go, tại sao ResponseWriter là một giá trị nhưng Request lại là một con trỏ?


82

Tôi đang học Go bằng cách viết một ứng dụng cho GAE và đây là chữ ký của một hàm xử lý:

func handle(w http.ResponseWriter, r *http.Request) {}

Tôi là con trỏ mới ở đây, vậy tại sao Requestđối tượng là con trỏ, nhưng ResponseWriterkhông phải? Có cần phải có nó theo cách này không hay đây chỉ là để làm cho một số loại mã dựa trên con trỏ nâng cao có thể thực hiện được?

Câu trả lời:


64

Những gì bạn nhận được wlà một con trỏ đến loại không được xuất http.responsenhưng cũng như ResponseWritermột giao diện, nó không hiển thị.

Từ server.go :

type ResponseWriter interface {
    ...
}

Mặt khác, rlà một con trỏ đến một cấu trúc cụ thể, do đó cần phải chuyển một tham chiếu một cách rõ ràng.

Từ request.go :

type Request struct {
    ...
}

28

Đây http.ResponseWriterlà một giao diện và các kiểu hiện có triển khai giao diện này là các con trỏ. Điều đó có nghĩa là không cần sử dụng một con trỏ đến giao diện này, vì nó đã được "hỗ trợ" bởi một con trỏ. Khái niệm này được mô tả một chút bởi một trong những người phát triển go ở đây Mặc dù một kiểu triển khai http.ResponseWriter không cần phải là một con trỏ, nó sẽ không thực tế, ít nhất là không trong máy chủ go http.

http.Requestkhông phải là một giao diện, nó chỉ là một cấu trúc và vì chúng tôi muốn thay đổi cấu trúc này và yêu cầu máy chủ web nhìn thấy những thay đổi đó, nó phải là một con trỏ. Nếu đó chỉ là một giá trị struct, chúng tôi sẽ chỉ sửa đổi một bản sao của nó mà máy chủ web gọi mã của chúng tôi không thể nhìn thấy.


1
Tôi không nghĩ rằng điều này là đúng. Các giá trị đằng sau con trỏ có thể triển khai các giao diện giống như các giá trị, vì vậy không cần phân biệt ở đây. Một kiểu có kiểu cơ sở int có thể thỏa mãn một giao diện mà không cần là một con trỏ hoặc được hỗ trợ bởi một giao diện.
nemo

2
Tôi không có ý ám chỉ rằng tất cả những thứ triển khai giao diện phải là con trỏ. Một cái gì đó giống như một ResponseWriter cần phải sửa đổi trạng thái của giá trị đằng sau giao diện để làm bất cứ điều gì hữu ích và điều đó sẽ yêu cầu giá trị đó là một loại con trỏ (như bài đăng trên blog mà tôi đã liên kết cũng nói). Nhưng có, về mặt lý thuyết, http.ResponseWriter có thể được thực thi bởi một int (mà các phương thức của nó không bao giờ có thể thay đổi giá trị int đó).
nos

Câu trả lời này rất hữu ích. Liên kết đó là vô giá, với lời giải thích rõ ràng cho những người trong chúng ta mới làm quen với con trỏ. "Nghĩa là, mặc dù không có điểm đánh dấu rõ ràng, các đối tượng giao diện thường hoạt động giống như con trỏ. Điều này có thể gây nhầm lẫn cho đến khi bạn hiểu điều gì đang thực sự diễn ra."
Cody Django

1
Phần về Yêu cầu thực sự sai, hãy xem câu trả lời của tôi stackoverflow.com/a/56875204/989991
joakim

6

Như đã đề cập chính xác trong nhiều câu trả lời khác ở đây và ở những nơi khác, ResponseWriterlà một giao diện và ý nghĩa của điều này đã được mô tả chi tiết trong các câu trả lời SO và blog.

Điều tôi muốn giải quyết là điều tôi cảm thấy là quan niệm sai lầm lớn — và nguy hiểm — ở đây, rằng lý do yêu cầu được thông qua bởi "tham chiếu" (mặc dù điều như vậy không thực sự tồn tại trong cờ vây ) là "chúng tôi muốn thực hiện thay đổi nó hiển thị cho máy chủ ".

Trích dẫn một số câu trả lời:

[..] nó chỉ là một cấu trúc và vì chúng tôi muốn thay đổi cấu trúc này và để máy chủ web thấy những thay đổi đó, nó phải là một con trỏ [..] VẬY

[..] các thay đổi đối với Yêu cầu của trình xử lý cần hiển thị với máy chủ, vì vậy chúng tôi chỉ chuyển nó bằng tham chiếu thay vì theo giá trị [..] VẬY

Điều này là sai ; trên thực tế , tài liệu cảnh báo rõ ràng chống giả mạo / thay đổi yêu cầu :

Ngoại trừ việc đọc nội dung, trình xử lý không nên sửa đổi Yêu cầu đã cung cấp.

Hoàn toàn ngược lại, không? :-)

Nếu bạn muốn thay đổi yêu cầu, ví dụ như nối tiêu đề theo dõi trước khi chuyển nó cho trình xử lý tiếp theo trong chuỗi phần mềm trung gian, bạn phải sao chép yêu cầu và chuyển phiên bản đã sao chép xuống chuỗi.

Đội cờ vây đã đưa ra yêu cầu thay đổi hành vi để cho phép sửa đổi yêu cầu đến nhưng việc thay đổi điều gì đó như thế này có thể dẫn đến ít nhất một số mã hiện có bị phá vỡ bất ngờ.

Tại sao lại sử dụng con trỏ nếu chúng ta đang nói rõ ràng với mọi người rằng đừng thay đổi yêu cầu? Hiệu suất , Requestlà một cấu trúc lớn và việc sao chép nó có thể làm giảm hiệu suất, đặc biệt là với các chuỗi phần mềm trung gian dài. Nhóm nghiên cứu đã phải cân bằng, chắc chắn không phải là một giải pháp lý tưởng, nhưng sự cân bằng rõ ràng nằm ở khía cạnh hiệu suất ở đây (thay vì an toàn API).


Đây là câu trả lời cuối cùng có ý nghĩa đối với tôi.
Jimi

1

Lý do tại sao nó là một con trỏ đến Yêu cầu rất đơn giản: các thay đổi đối với Yêu cầu của trình xử lý cần được hiển thị cho máy chủ, vì vậy chúng tôi chỉ chuyển nó bằng tham chiếu thay vì theo giá trị.

Nếu bạn đào sâu vào mã thư viện net / http, bạn sẽ thấy rằng ResponseWriter là một giao diện cho phản hồi cấu trúc không được báo cáo và chúng tôi đang chuyển cấu trúc bằng cách tham chiếu (chúng tôi đang chuyển một con trỏ để phản hồi) chứ không phải theo giá trị . ResponseWriter là một giao diện mà trình xử lý sử dụng để tạo phản hồi HTTP. Cấu trúc thực tế sao lưu ResponseWriter là http.response cấu trúc không được báo cáo. Bởi vì nó không được báo cáo, bạn không thể sử dụng nó trực tiếp; bạn chỉ có thể sử dụng nó thông qua giao diện ResponseWriter.

Nói cách khác, cả hai tham số đều được truyền vào bằng tham chiếu; nó chỉ là chữ ký phương thức lấy một ResponseWriter, một giao diện cho một con trỏ đến một cấu trúc, vì vậy nó trông giống như thể nó được chuyển vào bằng giá trị.


Có ý nghĩa hơn câu trả lời ban đầu với tôi
Venkata SSKM Chaitanya

Phần về Yêu cầu thực sự là sai, xem câu trả lời của tôi stackoverflow.com/a/56875204/989991
Joakim

0

Tôi nghĩ rằng lý do chính để Requestđối tượng được truyền như một con trỏ là Bodytrường. Đối với một yêu cầu HTTP nhất định, phần nội dung chỉ chúng tôi có thể đọc một lần. Nếu Requestđối tượng được nhân bản, cũng giống như nếu nó không được chuyển qua dưới dạng con trỏ, chúng ta sẽ có hai đối tượng với thông tin khác nhau về số lượng đã được đọc từ phần thân.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.