Guest User

Untitled

a guest
Oct 21st, 2016
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.91 KB | None | 0 0
  1. // Traverses an arbitrary struct and translates all stings it encounters
  2. //
  3. // I haven't seen an example for reflection traversing an arbitrary struct, so
  4. // I want to share this with you. If you encounter any bugs or want to see
  5. // another example please comment.
  6. //
  7. // The MIT License (MIT)
  8. //
  9. // Copyright (c) 2014 Heye Vöcking
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining a copy
  12. // of this software and associated documentation files (the "Software"), to deal
  13. // in the Software without restriction, including without limitation the rights
  14. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. // copies of the Software, and to permit persons to whom the Software is
  16. // furnished to do so, subject to the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be included in
  19. // all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. // THE SOFTWARE.
  28.  
  29. package main
  30.  
  31. import (
  32. "fmt"
  33. "reflect"
  34. )
  35.  
  36. var dict = map[string]string{
  37. "Hello!": "Hallo!",
  38. "What's up?": "Was geht?",
  39. "translate this": "übersetze dies",
  40. "point here": "zeige hier her",
  41. "translate this as well": "übersetze dies auch...",
  42. "and one more": "und noch eins",
  43. "deep": "tief",
  44. }
  45.  
  46. type I interface{}
  47.  
  48. type A struct {
  49. Greeting string
  50. Message string
  51. Pi float64
  52. }
  53.  
  54. type B struct {
  55. Struct A
  56. Ptr *A
  57. Answer int
  58. Map map[string]string
  59. StructMap map[string]interface{}
  60. Slice []string
  61. }
  62.  
  63. func create() I {
  64. // The type C is actually hidden, but reflection allows us to look inside it
  65. type C struct {
  66. String string
  67. }
  68.  
  69. return B{
  70. Struct: A{
  71. Greeting: "Hello!",
  72. Message: "translate this",
  73. Pi: 3.14,
  74. },
  75. Ptr: &A{
  76. Greeting: "What's up?",
  77. Message: "point here",
  78. Pi: 3.14,
  79. },
  80. Map: map[string]string{
  81. "Test": "translate this as well",
  82. },
  83. StructMap: map[string]interface{}{
  84. "C": C{
  85. String: "deep",
  86. },
  87. },
  88. Slice: []string{
  89. "and one more",
  90. },
  91. Answer: 42,
  92. }
  93. }
  94.  
  95. func main() {
  96. // Some example test cases so you can mess around and see if it's working
  97. // To check if it's correct look at the output, no automated checking here
  98.  
  99. // Test the simple cases
  100. {
  101. fmt.Println("Test with nil pointer to struct:")
  102. var original *B
  103. translated := translate(original)
  104. fmt.Println("original: ", original)
  105. fmt.Println("translated:", translated)
  106. fmt.Println()
  107. }
  108. {
  109. fmt.Println("Test with nil pointer to interface:")
  110. var original *I
  111. translated := translate(original)
  112. fmt.Println("original: ", original)
  113. fmt.Println("translated:", translated)
  114. fmt.Println()
  115. }
  116. {
  117. fmt.Println("Test with struct that has no elements:")
  118. type E struct {
  119. }
  120. var original E
  121. translated := translate(original)
  122. fmt.Println("original: ", original)
  123. fmt.Println("translated:", translated)
  124. fmt.Println()
  125. }
  126. {
  127. fmt.Println("Test with empty struct:")
  128. var original B
  129. translated := translate(original)
  130. fmt.Println("original: ", original, "->", original.Ptr)
  131. fmt.Println("translated:", translated, "->", translated.(B).Ptr)
  132. fmt.Println()
  133. }
  134.  
  135. // Imagine we have no influence on the value returned by create()
  136. created := create()
  137. {
  138. // Assume we know that `created` is of type B
  139. fmt.Println("Translating a struct:")
  140. original := created.(B)
  141. translated := translate(original)
  142. fmt.Println("original: ", original, "->", original.Ptr)
  143. fmt.Println("translated:", translated, "->", translated.(B).Ptr)
  144. fmt.Println()
  145. }
  146. {
  147. // Assume we don't know created's type
  148. fmt.Println("Translating a struct wrapped in an interface:")
  149. original := created
  150. translated := translate(original)
  151. fmt.Println("original: ", original, "->", original.(B).Ptr)
  152. fmt.Println("translated:", translated, "->", translated.(B).Ptr)
  153. fmt.Println()
  154. }
  155. {
  156. // Assume we don't know B's type and want to pass a pointer
  157. fmt.Println("Translating a pointer to a struct wrapped in an interface:")
  158. original := &created
  159. translated := translate(original)
  160. fmt.Println("original: ", (*original), "->", (*original).(B).Ptr)
  161. fmt.Println("translated:", (*translated.(*I)), "->", (*translated.(*I)).(B).Ptr)
  162. fmt.Println()
  163. }
  164. {
  165. // Assume we have a struct that contains an interface of an unknown type
  166. fmt.Println("Translating a struct containing a pointer to a struct wrapped in an interface:")
  167. type D struct {
  168. Payload *I
  169. }
  170. original := D{
  171. Payload: &created,
  172. }
  173. translated := translate(original)
  174. fmt.Println("original: ", original, "->", (*original.Payload), "->", (*original.Payload).(B).Ptr)
  175. fmt.Println("translated:", translated, "->", (*translated.(D).Payload), "->", (*(translated.(D).Payload)).(B).Ptr)
  176. fmt.Println()
  177. }
  178. }
  179.  
  180. func translate(obj interface{}) interface{} {
  181. // Wrap the original in a reflect.Value
  182. original := reflect.ValueOf(obj)
  183.  
  184. copy := reflect.New(original.Type()).Elem()
  185. translateRecursive(copy, original)
  186.  
  187. // Remove the reflection wrapper
  188. return copy.Interface()
  189. }
  190.  
  191. func translateRecursive(copy, original reflect.Value) {
  192. switch original.Kind() {
  193. // The first cases handle nested structures and translate them recursively
  194.  
  195. // If it is a pointer we need to unwrap and call once again
  196. case reflect.Ptr:
  197. // To get the actual value of the original we have to call Elem()
  198. // At the same time this unwraps the pointer so we don't end up in
  199. // an infinite recursion
  200. originalValue := original.Elem()
  201. // Check if the pointer is nil
  202. if !originalValue.IsValid() {
  203. return
  204. }
  205. // Allocate a new object and set the pointer to it
  206. copy.Set(reflect.New(originalValue.Type()))
  207. // Unwrap the newly created pointer
  208. translateRecursive(copy.Elem(), originalValue)
  209.  
  210. // If it is an interface (which is very similar to a pointer), do basically the
  211. // same as for the pointer. Though a pointer is not the same as an interface so
  212. // note that we have to call Elem() after creating a new object because otherwise
  213. // we would end up with an actual pointer
  214. case reflect.Interface:
  215. // Get rid of the wrapping interface
  216. originalValue := original.Elem()
  217. // Create a new object. Now new gives us a pointer, but we want the value it
  218. // points to, so we have to call Elem() to unwrap it
  219. copyValue := reflect.New(originalValue.Type()).Elem()
  220. translateRecursive(copyValue, originalValue)
  221. copy.Set(copyValue)
  222.  
  223. // If it is a struct we translate each field
  224. case reflect.Struct:
  225. for i := 0; i < original.NumField(); i += 1 {
  226. translateRecursive(copy.Field(i), original.Field(i))
  227. }
  228.  
  229. // If it is a slice we create a new slice and translate each element
  230. case reflect.Slice:
  231. copy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
  232. for i := 0; i < original.Len(); i += 1 {
  233. translateRecursive(copy.Index(i), original.Index(i))
  234. }
  235.  
  236. // If it is a map we create a new map and translate each value
  237. case reflect.Map:
  238. copy.Set(reflect.MakeMap(original.Type()))
  239. for _, key := range original.MapKeys() {
  240. originalValue := original.MapIndex(key)
  241. // New gives us a pointer, but again we want the value
  242. copyValue := reflect.New(originalValue.Type()).Elem()
  243. translateRecursive(copyValue, originalValue)
  244. copy.SetMapIndex(key, copyValue)
  245. }
  246.  
  247. // Otherwise we cannot traverse anywhere so this finishes the the recursion
  248.  
  249. // If it is a string translate it (yay finally we're doing what we came for)
  250. case reflect.String:
  251. translatedString := dict[original.Interface().(string)]
  252. copy.SetString(translatedString)
  253.  
  254. // And everything else will simply be taken from the original
  255. default:
  256. copy.Set(original)
  257. }
  258.  
  259. }
Add Comment
Please, Sign In to add comment