Asserting Go Types?

agolangf · · 1007 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I am attempting to assert a type assigned to a string. This is for a function that will be taking an interface{} value. The type is being loaded from a configuration file, so it will be be a string referencing a registered type.</p> <p><a href="http://play.golang.org/p/PoOTedQeaV">http://play.golang.org/p/PoOTedQeaV</a></p> <p>This seems awful clunky.</p> <hr/>**评论:**<br/><br/>jmank88: <pre><p>You can use type assertions, in the form: interface.(type)</p> <p>This can be used to perform a type conversion, and also returns an optional boolean as a second parameter, indicating if the conversion was legal/successful.</p> <p>Here is a simplified example based on your playground code: <a href="http://play.golang.org/p/B9q-yvzb5-" rel="nofollow">http://play.golang.org/p/B9q-yvzb5-</a></p> <p>Reference: <a href="https://golang.org/ref/spec#Type_assertions" rel="nofollow">https://golang.org/ref/spec#Type_assertions</a></p> <p>You can also switch on types: <a href="https://golang.org/ref/spec#Type_switches" rel="nofollow">https://golang.org/ref/spec#Type_switches</a></p></pre>jasonrichardsmith: <pre><p>But I can&#39;t map[string]type can I?</p></pre>jmank88: <pre><p>Not exactly. If you need a handle to a type in the form of a variable, than you may have to resort to reflection. Can you work around the map of types?</p> <p>You could do something like this: <a href="http://play.golang.org/p/UYnCnoKPW3" rel="nofollow">http://play.golang.org/p/UYnCnoKPW3</a></p> <p>The switch cases are fairly static, but you can include a set of strings and some additional logic to include/exclude keys from your config file. (e.g. If string not in set loaded from config, fail fast by returning false before evaluating the switch)</p> <p>Though I&#39;m not sure I understand enough of the full scope of the problem.</p></pre>jasonrichardsmith: <pre><p>Well I want to give developers the opportunity to add additional types.</p> <p>Essentially I am adding a microservice declaration and discovery system, to be used with tools with vulcand(plugable with other systems), where the parameters are declared via yaml. The service being developed is able to declare its other required microservices, and by doing such, discover the required parameters and value types for that services it will be consuming. This will allow me to autogenerate restful clients. That way the developer no longer has to know how to implement this one microservice he can just set his parameters and the client package will automatically generate the web request. </p> <p>It is here: <a href="https://github.com/mongolar/microservice" rel="nofollow">https://github.com/mongolar/microservice</a></p> <p>Don&#39;t read any of the docs, they are completely out of date. </p></pre>boomshroom: <pre><p><a href="http://play.golang.org/p/hepXxzxrdK" rel="nofollow">http://play.golang.org/p/hepXxzxrdK</a></p> <p>I&#39;ve cleaned up your code a bit by making TestType function take an interface{} and replacing your init function with a compound map literal. Also there&#39;s no reason to have </p> <pre><code>if something { return true } return false </code></pre> <p>when you can just do</p> <pre><code>return something </code></pre></pre>dchapes: <pre><p>I was going to say the same thing. However, you should use <code>var x = mytype{…}</code> (or <code>var x = somefunc()</code>) instead of <code>var x mytype = mytype{…}</code> (I think <code>golint</code> also points this out): <a href="https://play.golang.org/p/AINVSnn5FR" rel="nofollow">https://play.golang.org/p/AINVSnn5FR</a></p></pre>jerf: <pre><p>Use a &#34;class method&#34;. Go doesn&#39;t have class methods, but class methods are just methods that don&#39;t reference the instance variable.</p> <pre><code>type Microservice interface { Create(r request) Microservice Name() string Handle() // whatever else you need } var microservices = map[string]Microservice func RegisterMicroservice(ms Microservice) { // real code probably ought to check for name duplication microservices[ms.Name()] = ms } func DispatchToMicroservice(r request) { // router.Route apparently returns a string that identifies the // microservice to handle it... msType := microservices[router.Route(r)] ms := msType.Create(r) ms.Handle() } type SpecificMicroservice struct { r request } // the &#34;class method&#34;; note sm is never referenced. You can leave &#34;sm&#34; out // if you like. func (sm *SpecificMicroservice) Create(r request) Microservice { return &amp;SpecificMicroservice{r} } func (sm *SpecificMicroservice) Name() string { return &#34;specific&#34; } func (sm *SpecificMicroservice) Handle() { // whatever } func main() { // the other key; for the &#34;class method&#34; it is sufficient to create // the zero instance of the type, because it literally doesn&#39;t matter // what the contents are. RegisterMicroservice(&amp;SpecificMicroservice{}) // get on with the rest of the program... } </code></pre> <p>(this is just smashed out into this comment form so pardon if it has some small errors in it.)</p> <p><code>map[string]ThingThatCanCreateMoreOfItself</code> is a powerful pattern for this sort of registration.</p></pre>jasonrichardsmith: <pre><p>Well that architecture is not the problem. Constructing the microservices is really easy, Marshaling the random parameter types is the only complicated part, because they need to correlate to a string value.</p></pre>jerf: <pre><p>Well, generally, keep going with the same idea. Try to create interfaces that simply directly say what you actually want, which may involve returning other interface values.</p> <p>That said, there is a certain limit to this technique where eventually you will really start to miss generic types. Reflection can get around it but it&#39;s tedious and often slow. Still, people tend to underestimate the distance to that limit before they really start trying. You can also cheat a bit if the parameters can be JSON or XML that the encoding package can handle; those use reflection, but at least you don&#39;t have to expend the effort to write it yourself, it&#39;s all just library code. Also have a look at how the marshaling works with interfaces (see the encoding package itself for a couple of definitions) as it may provide some other useful techniques.</p></pre>Fwippy: <pre><p>I&#39;d recommend turning this inside-out a bit.</p> <p>Instead of using type <code>interface{}</code>, why not have instead require an interface like:</p> <pre><code>type Serializable interface { encoding.TextMarshaller encoding.TextUnmarshaller } </code></pre> <p>The developers know the most about what their datatypes are and what they need, and have the best access to the types in order to write clean marshalling code. If something like <code>encoding.json</code>works for them, implementation is easy for them. If it doesn&#39;t; you have even less hope of marshalling the data than they do.</p></pre>jasonrichardsmith: <pre><p>Well the idea here is to build a client to consume another microservice, based on the definition of the service that is pulled don from a tool like etcd. That way, they do need to know the field types, but don&#39;t know how or where the information is stored, because the client will make sure the htt.request is assembled as defined by the service and the parameters that were grabbed from configs. That way if a service changes it methods or anything like that their definition of http.Request building is defined in the client and not by the user.</p></pre>djherbis: <pre><p>Actually the standard library does something similar: </p> <p><a href="https://golang.org/pkg/encoding/gob" rel="nofollow">https://golang.org/pkg/encoding/gob</a> <a href="https://golang.org/src/encoding/gob/type.go?s=25464:25496#L810" rel="nofollow">https://golang.org/src/encoding/gob/type.go?s=25464:25496#L810</a></p></pre>jasonrichardsmith: <pre><p>Wow, thank you, this is exactly the sort of information I was looking for.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1007 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传