<p>I have a function that receives <code>v interface{}</code> as argument which can be <code>*T</code> or <code>[]*T</code>. I'd like that function to modify <code>v</code> for both cases. The <code>*T</code> case is working but I'd like some help for the <code>[]*T</code> case.</p>
<p>Here's some code: <a href="https://play.golang.org/p/tb6Yed5TCd">https://play.golang.org/p/tb6Yed5TCd</a></p>
<p>(Reflection is never clear I know but in this case I have no choice.)</p>
<hr/>**评论:**<br/><br/>ston1th: <pre><p>I have a solution: <a href="https://play.golang.org/p/MfGJT1oOhN" rel="nofollow">https://play.golang.org/p/MfGJT1oOhN</a></p>
<p>But please keep in mind that this is not recommended.</p>
<p>Edit: simpler solution</p></pre>nesigma: <pre><p>Amazing! You are a true reflection-dark-arts-voodoo master! :D Thanks a lot!</p></pre>mordfustang21: <pre><p>Couldn't you use a type switch?
<a href="https://play.golang.org/p/iOryUx4ozN" rel="nofollow">https://play.golang.org/p/iOryUx4ozN</a></p></pre>nesigma: <pre><p>I can't use a type switch because T is not known by foo and the helper returns <code>[]interface{}</code>. Besides the problem is not how to distinguish between slice and and struct. That is taken care off. The problem is how to fill <code>v</code> with data in case <code>v</code> is a slice. In other words I am trying to figure out how to do the <code>v = s</code> part of the code.</p></pre>: <pre><p>[deleted]</p></pre>nesigma: <pre><p>The goal is to fill <code>v</code> with data when it is passed as an argument in foo. Returning aka <code>v := foo()</code> or <code>v := helper()</code> is not allowed.</p></pre>: <pre><p>[deleted]</p></pre>nesigma: <pre><p>Well then I should have also added that the signature of <code>foo(v interface{})</code> should also be unmodified and that helper has to be used inside of foo.</p>
<p>The reason is that I am trying to create a function that fills <code>v</code> with data for both cases <code>*T</code> and <code>[]*T</code> in the same exact way. In practice that means:</p>
<p>Case <code>*T</code></p>
<pre><code>t := new(T)
foo(t)
// now t is filled with data
</code></pre>
<p>Case <code>[]*T</code></p>
<pre><code>var t []*T
foo(t)
// now t is filled with slice data
</code></pre>
<p>The <code>helper</code> func is the provider of data for the second case.</p>
<p>The first case is solved and now I am trying to figure out how to do the second case.</p></pre>: <pre><p>[deleted]</p></pre>nesigma: <pre><p>I do not know the type of <code>t</code>, that's why I named the type <code>T</code>. Sorry for the confusion.</p>
<blockquote>
<p>What is the purpose of foo()?</p>
</blockquote>
<p>The purpose of foo is to fill <code>v</code> with data in the same exact way for both cases. Imagine there are two data providers which I cannot change.</p>
<p><code>helperOne(v interface{})</code></p>
<p><code>helperSlice() []interface{}</code></p>
<p>So the purpose of foo is to allow to use those two functions inside it seamlessly as I described above.</p></pre>: <pre><p>[deleted]</p></pre>tv64738: <pre><p>Seems like you are missing the fundamentals of slice behavior, and what append actually does, and reflection is preventing you from realizing that.</p>
<p>Mutating a local copy of a slice isn't very useful.</p>
<p><a href="https://blog.golang.org/slices" rel="nofollow">https://blog.golang.org/slices</a></p></pre>nesigma: <pre><blockquote>
<p>Mutating a local copy of a slice isn't very useful.</p>
</blockquote>
<p>What do you mean? Is it impossible for <code>v</code> to be filled with data in case of a slice?</p></pre>tv64738: <pre><p>Appending to a copy of a slice doesn't change the original slice.</p></pre>nesigma: <pre><blockquote>
<p>Appending to a copy of a slice doesn't change the original slice.</p>
</blockquote>
<p>Ok and how can I modify the original <code>v</code> slice then?</p></pre>tv64738: <pre><p>You don't. Read the blog post I linked to earlier.</p></pre>nesigma: <pre><blockquote>
<p>You don't. Read the blog post I linked to earlier.</p>
</blockquote>
<p>I did but I still don't get it.</p>
<p>What if I pass a pointer to a slice as an argument?</p></pre>cathalgarvey: <pre><p>A slice is a pointer to an underlying array. You can append to the slice and it will append to the array if there is room, or reallocate if there is not.</p>
<p>If there is room, great: the slice is equivalent to the array. If not, you can't consider them equivalent. You can use <code>len</code> and <code>cap</code> to get the length and total capacity of the underlying array (currently) under a slice. Note slices dynamically reallocate using the <code>append</code> function if needed.</p>
<p>Back to your core Q: it sounds like you want generics, but Go hates Generics. So your options are: use code-generators to mimic Generics (several options exist out there), find another way, or learn Rust instead. :P</p></pre>nesigma: <pre><blockquote>
<p>A slice is a pointer to an underlying array. You can append to the slice and it will append to the array if there is room, or reallocate if there is not.</p>
</blockquote>
<p>That is not correct. According to <a href="https://blog.golang.org/slices" rel="nofollow">https://blog.golang.org/slices</a> a slice is a struct value holding a pointer and a length. </p>
<p>This is most likely the reason why passing <code>[]*T</code> as an argument to the function in my code (through <code>v interface{}</code>) makes it impossible to change the slice header. The reason is because the slice struct gets copied or something like that. I do not understand it 100% myself.</p>
<blockquote>
<p>or learn Rust instead</p>
</blockquote>
<p>Rust is way too complex for me. I mean I already have trouble understanding some Go stuff.</p></pre>cathalgarvey: <pre><p>Sorry, you are correct: I was misusing the word "Pointer". Well, AFAIK a slice <em>is</em> a literal pointer, because it's nullable, but you're correct that the referred-to data is a struct.</p></pre>tv64738: <pre><p>That would work, but would read a differently from typical Go (it's not <code>append(&s, x)</code>).</p>
<p>Better advice comes after you talk about actual use cases.</p></pre>nesigma: <pre><p>I am trying to write a function that wraps up the functionality of two data providers in the exact same way.</p>
<p>One provider accepts *T as an argument and fills it with data.</p>
<p><code>helperOne(v interface{})</code></p>
<p>The other provider returns []interface{} and it meant to fill []*T with data.</p>
<p><code>helperSlice() []interface{}</code></p>
<p>So I am trying to create a function <code>foo(v interface{})</code> that no matter what the user throws in the argument (<code>*T</code> or <code>[]*T</code>) it uses the correct helper inside and fills in the data in both cases in the exact same way, seamlessly with no returning.</p>
<p>In any case, <a href="https://www.reddit.com/r/golang/comments/66qwet/could_anyone_help_me_with_some_reflection_voodoo/dgm9t4g/" rel="nofollow">this</a> is the solution I was looking for!</p></pre>tv64738: <pre><p>That's not a use case..</p></pre>victrolla: <pre><p>Sorry I'm on mobile so I may be missing something obvious. </p>
<p>I'm unclear about why reflection is needed here. It seems to me that your function signature could change to accept variadic arguments. </p>
<p>'func foo(args interface{}...) {
// operate on args as a slice of interface types
}'</p>
<p>Am I missing something obvious here?</p></pre>nesigma: <pre><p>This is a very cool idea but unfortunately it doesn't work.</p>
<p>New Signature: </p>
<pre><code>func foo(v ...interface{}) {}
</code></pre>
<p>New Call: </p>
<pre><code>var t []*T
foo(t...)
</code></pre>
<p>Gives:</p>
<pre><code>cannot use t (type []*T) as type []interface {} in argument to foo
</code></pre></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传