<p>Hello all,</p>
<p>Python dev picking up golang again.</p>
<p>I'm toying with writing an Arguments module, that uses the flag pkg.</p>
<p>I want to define a struct as such:</p>
<pre><code>type argument struct {
name string
value ???
argType reflect.Kind
}
</code></pre>
<p>I want the value to have type of argType, and I want to be able to be able to call .Value() on my argument to retrieve the appropriately typed value, without having to do any extra type assertion.</p>
<p>Is there an idiomatic way to do this? Coming from a dynamically typed language, I've forgotten all my statically typed prowess.</p>
<p>Should I avoid using reflection? The only way I see of doing this is with reflection, setting value as type interface{}, and using type assertion to get appropriate values type back, but that's messy imo. I don't want the user who calls .Value() to have to do some further type assertion.</p>
<p>Any help would be greatly appreciated!</p>
<hr/>**评论:**<br/><br/>skidooer: <pre><p>I would advocate that it is best to explain what you want to do, rather than how you are doing it. It is possible that a completely different approach would better solve for what you are trying to accomplish.</p>
<p>With that said, on the limited information here, why not provide methods for the various types that may be returned? .Int() returns an int, .String() returns a string, etc. That way the caller doesn't have to worry about asserting the type. You can do it for them.</p></pre>ChristophBerger: <pre><p>I second this. Be aware of <a href="http://xyproblem.info/">the XY Problem</a>.</p></pre>trchttrhydrn: <pre><p>I just did this to myself. </p>
<p>I started with a situation where I needed to have a cheap way of mutual exclusion on numerous entities, so I used a uint32 with a simple atomic compare-and-swap spinlock.</p>
<p>Then I realized I needed to support RLock() and Lock(), and more than this, I needed a queue'd sort of fairness, to ensure that numerous RLock()'s couldn't starve a Lock().</p>
<p>So fine, now I had an array-based queueing lock, allowing each locker to wait on their own core-local variable at a given index in the array. After each check, they would sleep for a bit before trying again to see if they had reached the queue head. Each Unlock sets the locker's array variable to 0 and sets the next one to 1 (the next locker will now wake up and see it's at the queue head).</p>
<p>I realized I had in the end just reimplemented the functionality (if not the implementation) of RWMutex, and poorly, since it caused 100 times more voluntary context-switches than RWMutex when I benchmarked it. LOL. My simple lightweight uint32 had become a poor replacement for what I should have used all along.</p>
<p>Well I guess it's not <em>strictly</em> the same problem. More like a problem of not reevaluating the possible solutions as my requirements expanded, and continuing to modify my solution which was reached when requirements were different.</p></pre>iamdevquestionmark: <pre><p>Yeah, this seems to fit my issue to a T lol. Thanks :) I'll reply to poster above</p></pre>iamdevquestionmark: <pre><p>Fair enough, here's a more indepth description of what I want to do: </p>
<p>I have a binary which can be called with certain options/arguments. I wanted to make argument definition as easy as possible, and have all these arguments checked (for correctness/required/etc) in one place by looping over all defined arguments. </p>
<p>Furthermore, I wanted to use these argument values without having to do any type assertion or reflection (for which - my initial assumptions are correct - this is impossible). </p>
<p>Here's an SSCCE, on playground: <a href="https://play.golang.org/p/a7Pi_XQgcZj" rel="nofollow">https://play.golang.org/p/a7Pi_XQgcZj</a> </p>
<p>I'd heartily appreciate any suggestions. I know it's messy, i wrote it last night to try out whether or not i could try arbitrary values.</p></pre>beknowly: <pre><p>Code generation is your friend.</p>
<p>Check out how urfave/cli does it: <a href="https://github.com/urfave/cli/blob/master/flag_generated.go#L60" rel="nofollow">https://github.com/urfave/cli/blob/master/flag_generated.go#L60</a></p></pre>danredux: <pre><p>This is impossible. The compiler needs to know the function signature. Even using generics would require passing in the type. Use the empty interface and type assert it.</p>
<p>Better yet, if you're wanting to learn Go, I'd suggest you stop trying to force it to be like Python. While right now you're unhappy you can't just return anything and have the runtime handle this "types" stuff, later you'll love knowing that your variables actually hold what you think they hold. You'll hate Go if you try to write it like Python.</p></pre>iamdevquestionmark: <pre><p>Great points. These are pitfalls I'm trying to avoid, hence the question about how to go about it idiomatically. </p>
<p>Thanks :)</p></pre>earthboundkid: <pre><blockquote>
<p>Should I avoid using reflection?</p>
</blockquote>
<p>Yes.</p></pre>spacemit: <pre><p>Isn't reflection in Go really fast? (Basically just dereferencing a pointer)</p></pre>earthboundkid: <pre><p>That’s not why it sucks. It sucks because you’re trying to do an end run around the type system and in almost all cases (everything except serialization/deserialization) that’s a mistake and you’ll have a better system by going with the type system. </p>
<p>The same applies in Python, by the way. For Python, you should almost never use metaclasses or look at types at all. </p></pre>ihsw: <pre><blockquote>
<p>without having to do any extra type assertion.</p>
</blockquote>
<p>This is not really possible, your return type has to be <em>something</em>. As you said you can perform type-switches with <code>interface{}</code> being the type of <code>value</code> but there's not much else you can do here. Welcome to Go, going against the grain is the most effective way to frustrate yourself.</p></pre>iamdevquestionmark: <pre><p>Yeah, I feared as much. It'll just be easier to store all parsed args as strings, and convert before using them as necessary. </p>
<p>Thanks for the quick reply! :)</p></pre>ihsw: <pre><blockquote>
<p>strings</p>
</blockquote>
<p>Why not just byte arrays? If you're going to go the marshaling/unmarshaling route, you can make it more interesting and store json blobs or protobuf blobs.</p></pre>iamdevquestionmark: <pre><p>Yeah I've had a couple of suggestions for using a byte array. </p></pre>mixiegen: <pre><pre><code>type argument struct {
name string
value interface{}
}
</code></pre>
<p>Go doesn't support custom generic, so type assertion is required. </p></pre>weberc2: <pre><p>This is a runtime type anyway, so generics wouldn't help.</p></pre>beknowly: <pre><p>?</p>
<pre><code>data Argument a = Argument { name :: String , value :: a }
readRandomAssArg :: (Read a) => (String, String) -> Argument a
readRandomAssArg (name, raw) = Argument { name = name , value = read raw }
helloInt :: Argument Int
helloInt = readRandomAssArg ("hello", "1234")
helloBool :: Argument Bool
helloBool = readRandomAssArg ("hello", "True")
</code></pre></pre>weberc2: <pre><p>Those aren’t runtime types; they’re still static.</p></pre>beknowly: <pre><p>Yeah that's the idea with generics... Things that would otherwise be runtime types can be encoded in the type system to make them compile time.</p></pre>weberc2: <pre><blockquote>
<p>I want to be able to be able to call .Value() on my argument to retrieve the appropriately typed value</p>
</blockquote>
<p>I think you're confusing static and runtime types. Because <code>value</code> can be anything at runtime, it should have the type <code>interface{}</code> (the static type for a value that can have any time at runtime). Any time you want to assert that the runtime type in an <code>interface{}</code> is a particular static type, you need to use a type assertion. And to be clear, this isn't a limitation in Go, it's fundamental to types in general (as a mathematical concept) so it applies to every programming language (including languages like Python and JavaScript, where everything is implicitly an <code>interface{}</code>).</p></pre>iamdevquestionmark: <pre><p>You are correct. I did indeed muddle up static and runtime types. Thanks for the reply!</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传