Golang如何嵌入一个带有额外隐藏方法的接口?

huangapple go评论120阅读模式
英文:

Golang embed an interface with additional hidden methods?

问题

我想在一个结构体中嵌入一个http.ResponseWriter。这样做是可以的,它确保我的结构体也实现了http.ResponseWriter接口:

  1. type MyWriter struct {
  2. BytesWritten int
  3. http.ResponseWriter
  4. }

然而,尽管通常嵌入的http.ResponseWriter实现了http.Hijackerhttp.CloseNotifierhttp.Flusher接口,但它不再实现这些接口。

有没有办法解决这个问题呢?

英文:

I want to embed a http.ResponseWriter in a struct. That's fine, it makes sure my struct also implements http.ResponseWriter:

  1. type MyWriter struct {
  2. BytesWritten int
  3. http.ResponseWriter
  4. }

However, it no longer implements http.Hijacker, http.CloseNotifier or http.Flusher even though the embedded http.ResponseWriter usually does.

Is there some way to do this?

答案1

得分: 2

如果你知道响应写入器满足问题中列出的所有接口,那么你可以这样做:

  1. type allResponseWriterInterfaces struct {
  2. http.ResponseWriter
  3. http.Hijacker
  4. http.CloseNotifier
  5. http.Flusher
  6. }
  7. type MyWriter struct {
  8. BytesWritten int
  9. allResponseWriterInterfaces
  10. }
  11. ...
  12. aw, ok := w.(allResponseWriterInterfaces)
  13. if !ok {
  14. // 哎呀,响应写入器没有实现这些接口
  15. // 处理错误
  16. }
  17. mw := MyWriter{0, aw}

如果响应写入器不满足所有接口,情况就会变得混乱。参考Gorilla logger中处理响应写入器满足(http.ResponseWriter, http.CloseNotifier)或者(http.ResponseWriter, http.CloseNotifier, http.Hijacker)的示例。

英文:

If you know that the response writer satisfies all of the interfaces listed in the question, then you can do this:

  1. type allResponseWriterInterfaces {
  2. http.ResponseWriter
  3. http.Hijacker
  4. http.CloseNotifier
  5. http.Flusher
  6. }
  7. type MyWriter struct {
  8. BytesWritten int
  9. allResponseWriterInterfaces
  10. }
  11. ...
  12. aw, ok := w.(allResponseWriterInterfaces)
  13. if !ok {
  14. // oops, response writer does not implement the interfaces
  15. // handle the error
  16. }
  17. mw := MyWriter{0, aw}

It get's messy if the response writer does not satisfy all of the interfaces. See the Gorilla logger for an example of handling the case where the response writer satisfies (http.ResponseWriter, http.CloseNotifier) or (http.ResponseWriter, http.CloseNotifier, http.Hijacker).

答案2

得分: 0

一种解决方案是暴力解法,实际上实现所有的排列。我尝试过这种方法,发现它非常痛苦。总共有18种排列!

所以这里有一个通用的包装器。优点是你可以多次重复使用这个包装器。

关键是定义一个接口,如下所示:

// ResponseWriterTo可以将请求代理到底层的http.ResponseWriter。
// 它与CustomResponseWriter一起使用,用于包装具有自定义行为的http.ResponseWriter。
type ResponseWriterTo interface {
HeaderTo(w http.ResponseWriter) http.Header
WriteHeaderTo(w http.ResponseWriter, s int)
WriteTo(w http.ResponseWriter, b []byte) (n int, err error)

  1. // http.ResponseWriter有时会实现其他方法。
  2. CloseNotifyTo(w http.CloseNotifier) <-chan bool
  3. FlushTo(w http.Flusher)
  4. HijackTo(w http.Hijacker) (net.Conn, *bufio.ReadWriter, error)
  5. // ReaderFrom用于优化从TCP连接或文件中读取的http包。
  6. ReadFromTo(w io.ReaderFrom, r io.Reader) (n int64, err error)

}

这样我们就可以定义一个自定义的包装器函数(这是冗长的部分):

// CustomResponseWriter创建一个http.ResponseWriter,它实现了尽可能多的基本http.ResponseWriter的隐藏接口。
func CustomResponseWriter(base http.ResponseWriter, custom ResponseWriterTo) http.ResponseWriter {
rw := &customResponseWriter{base: base, custom: custom}

  1. // 基本的http.ResponseWriter可以实现许多隐藏接口,所以检查所有的排列
  2. type HCFR interface {
  3. http.ResponseWriter
  4. http.Hijacker
  5. http.CloseNotifier
  6. http.Flusher
  7. io.ReaderFrom
  8. }
  9. if _, ok := base.(HCFR); ok {
  10. return struct {
  11. HCFR
  12. }{rw}
  13. }
  14. type HCF interface {
  15. http.ResponseWriter
  16. http.Hijacker
  17. http.CloseNotifier
  18. http.Flusher
  19. }
  20. if _, ok := base.(HCF); ok {
  21. return struct {
  22. HCF
  23. }{rw}
  24. }
  25. // 其他排列...
  26. return struct {
  27. http.ResponseWriter
  28. }{rw}

}

// customResponseWriter允许我们将ResponseWriterTo适配到ResponseWriter。
type customResponseWriter struct {
base http.ResponseWriter
custom ResponseWriterTo
}

func (w *customResponseWriter) Header() http.Header { return w.custom.HeaderTo(w.base) }
func (w *customResponseWriter) Write(b []byte) (int, error) { return w.custom.WriteTo(w.base, b) }
func (w *customResponseWriter) WriteHeader(s int) { w.custom.WriteHeaderTo(w.base, s) }
func (w *customResponseWriter) CloseNotify() <-chan bool {
return w.custom.CloseNotifyTo(w.base.(http.CloseNotifier))
}
func (w *customResponseWriter) Flush() { w.custom.FlushTo(w.base.(http.Flusher)) }
func (w *customResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return w.custom.HijackTo(w.base.(http.Hijacker))
}
func (w *customResponseWriter) ReadFrom(r io.Reader) (n int64, err error) {
return w.custom.ReadFromTo(w.base.(io.ReaderFrom), r)
}

这个想法是将正确的接口嵌入到一个结构体中。然后只有"正确"的方法被暴露出来。

英文:

One solution is the brute-force solution. Actually implement all permutations. I tried this and found out how painful it is. There are 18 permutations!

So here is a general-purpose wrapper. The advantage is that you can re-use this wrapper as many times as you want.

The key is to define an interface like so:

  1. // ResponseWriterTo can proxy requests to an underlying http.ResponseWriter.
  2. // It is used with CustomResponseWriter to wrap an http.ResponseWriter with
  3. // custom behavior.
  4. type ResponseWriterTo interface {
  5. HeaderTo(w http.ResponseWriter) http.Header
  6. WriteHeaderTo(w http.ResponseWriter, s int)
  7. WriteTo(w http.ResponseWriter, b []byte) (n int, err error)
  8. // Additional methods that http.ResponseWriter sometimes implements.
  9. CloseNotifyTo(w http.CloseNotifier) &lt;-chan bool
  10. FlushTo(w http.Flusher)
  11. HijackTo(w http.Hijacker) (net.Conn, *bufio.ReadWriter, error)
  12. // ReaderFrom is used by the http package to optimize reads from TCP
  13. // connections or from files.
  14. ReadFromTo(w io.ReaderFrom, r io.Reader) (n int64, err error)
  15. }

so that we can define a custom wrapper function (this is the verbose part):

  1. // CustomResponseWriter creates a http.ResponseWriter that implements as many
  2. // hidden interfaces from the base http.ResponseWriter as are available.
  3. func CustomResponseWriter(base http.ResponseWriter, custom ResponseWriterTo) http.ResponseWriter {
  4. rw := &amp;customResponseWriter{base: base, custom: custom}
  5. // the base http.ResponseWriter can implement many hidden interfaces,
  6. // so check all permutations
  7. type HCFR interface {
  8. http.ResponseWriter
  9. http.Hijacker
  10. http.CloseNotifier
  11. http.Flusher
  12. io.ReaderFrom
  13. }
  14. if _, ok := base.(HCFR); ok {
  15. return struct {
  16. HCFR
  17. }{rw}
  18. }
  19. type HCF interface {
  20. http.ResponseWriter
  21. http.Hijacker
  22. http.CloseNotifier
  23. http.Flusher
  24. }
  25. if _, ok := base.(HCF); ok {
  26. return struct {
  27. HCF
  28. }{rw}
  29. }
  30. type HCR interface {
  31. http.ResponseWriter
  32. http.Hijacker
  33. http.CloseNotifier
  34. io.ReaderFrom
  35. }
  36. if _, ok := base.(HCR); ok {
  37. return struct {
  38. HCR
  39. }{rw}
  40. }
  41. type HFR interface {
  42. http.ResponseWriter
  43. http.Hijacker
  44. http.Flusher
  45. io.ReaderFrom
  46. }
  47. if _, ok := base.(HFR); ok {
  48. return struct {
  49. HFR
  50. }{rw}
  51. }
  52. type CFR interface {
  53. http.ResponseWriter
  54. http.CloseNotifier
  55. http.Flusher
  56. io.ReaderFrom
  57. }
  58. if _, ok := base.(CFR); ok {
  59. return struct {
  60. CFR
  61. }{rw}
  62. }
  63. type HC interface {
  64. http.ResponseWriter
  65. http.Hijacker
  66. http.CloseNotifier
  67. }
  68. if _, ok := base.(HC); ok {
  69. return struct {
  70. HC
  71. }{rw}
  72. }
  73. type HF interface {
  74. http.ResponseWriter
  75. http.Hijacker
  76. http.Flusher
  77. }
  78. if _, ok := base.(HF); ok {
  79. return struct {
  80. HF
  81. }{rw}
  82. }
  83. type CF interface {
  84. http.ResponseWriter
  85. http.CloseNotifier
  86. http.Flusher
  87. }
  88. if _, ok := base.(CF); ok {
  89. return struct {
  90. CF
  91. }{rw}
  92. }
  93. type HR interface {
  94. http.ResponseWriter
  95. http.Hijacker
  96. io.ReaderFrom
  97. }
  98. if _, ok := base.(HR); ok {
  99. return struct {
  100. HR
  101. }{rw}
  102. }
  103. type CR interface {
  104. http.ResponseWriter
  105. http.CloseNotifier
  106. io.ReaderFrom
  107. }
  108. if _, ok := base.(CR); ok {
  109. return struct {
  110. CR
  111. }{rw}
  112. }
  113. type FR interface {
  114. http.ResponseWriter
  115. http.Flusher
  116. io.ReaderFrom
  117. }
  118. if _, ok := base.(FR); ok {
  119. return struct {
  120. FR
  121. }{rw}
  122. }
  123. type H interface {
  124. http.ResponseWriter
  125. http.Hijacker
  126. }
  127. if _, ok := base.(H); ok {
  128. return struct {
  129. H
  130. }{rw}
  131. }
  132. type C interface {
  133. http.ResponseWriter
  134. http.CloseNotifier
  135. }
  136. if _, ok := base.(C); ok {
  137. return struct {
  138. C
  139. }{rw}
  140. }
  141. type F interface {
  142. http.ResponseWriter
  143. http.Flusher
  144. }
  145. if _, ok := base.(F); ok {
  146. return struct {
  147. F
  148. }{rw}
  149. }
  150. type R interface {
  151. http.ResponseWriter
  152. io.ReaderFrom
  153. }
  154. if _, ok := base.(R); ok {
  155. return struct {
  156. R
  157. }{rw}
  158. }
  159. return struct {
  160. http.ResponseWriter
  161. }{rw}
  162. }
  163. // customResponseWriter allows us to adapt a ResponseWriterTo to a ResponseWriter.
  164. type customResponseWriter struct {
  165. base http.ResponseWriter
  166. custom ResponseWriterTo
  167. }
  168. func (w *customResponseWriter) Header() http.Header { return w.custom.HeaderTo(w.base) }
  169. func (w *customResponseWriter) Write(b []byte) (int, error) { return w.custom.WriteTo(w.base, b) }
  170. func (w *customResponseWriter) WriteHeader(s int) { w.custom.WriteHeaderTo(w.base, s) }
  171. func (w *customResponseWriter) CloseNotify() &lt;-chan bool {
  172. return w.custom.CloseNotifyTo(w.base.(http.CloseNotifier))
  173. }
  174. func (w *customResponseWriter) Flush() { w.custom.FlushTo(w.base.(http.Flusher)) }
  175. func (w *customResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  176. return w.custom.HijackTo(w.base.(http.Hijacker))
  177. }
  178. func (w *customResponseWriter) ReadFrom(r io.Reader) (n int64, err error) {
  179. return w.custom.ReadFromTo(w.base.(io.ReaderFrom), r)
  180. }

The idea is to embed the correct interface into a struct. Then only the "right" methods are exposed.

huangapple
  • 本文由 发表于 2015年12月22日 13:08:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/34408808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定