Type Assertion on Custom Type

xuanbao · · 475 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;m working with the stripe library and it has a type of &#39;Currency&#39; in it.</p> <pre><code>// Currency is the list of supported currencies. // For more details see https://support.stripe.com/questions/which-currencies-does-stripe-support. type Currency string </code></pre> <p>I have an interface like below (notice the Currency)</p> <pre><code>type ChargeObject struct { Desc string // The charge description. Describe what they purchased. Source string // The token supplied by Stripe in place of a card. Amount uint64 // In pennies Currency interface{} // To be type-asserted in the Charge function } </code></pre> <p>Some of my code:</p> <pre><code>curr, ok := obj.Currency.(stripe.Currency) if !ok { return response, fmt.Errorf(&#34;Currency &#39;%v&#39; could not be converted to stripe.Currency.&#34;, obj.Currency) } </code></pre> <p>The error I&#39;m getting when I use &#34;usd&#34; as a param:</p> <pre><code>Other error occurred: Currency &#39;usd&#39; could not be converted to stripe.Currency. </code></pre> <p>This works if I create the struct with stripe.Currency = &#34;usd&#34;. Why doesn&#39;t it work when I type-assert it?</p> <p>If you&#39;re wondering why I&#39;m not just using stripe.Currency instead of interface, I&#39;m trying to make some interfaces around charging Paypal and Stripe depending on what I want to do in the future. So Currency needs to be flexible on type.</p> <hr/>**评论:**<br/><br/>ChristophBerger: <pre><p>What do you mean by using &#34;usd&#34; as a param? How does this part of the code look like? </p></pre>natdm: <pre><p>Using the string &#34;usd&#34; as the value of Currency. It works if I say that Currency needs to be a stripe.Currency instead of interface{}, but since stripe.Currency is a string, why can&#39;t it be type-asserted to stripe.Currency?</p> <pre><code> testAcct := stripe.NewStripe(keys) testChargeObj := &amp;chargeable.ChargeObject{ Amount: 1000, Desc: &#34;Test Charge card ID card_&lt;id&gt;&#34;, Currency: &#34;usd&#34;, Source: &#34;tok_&lt;tok&gt;&#34;, } testCharge(testAcct, testChargeObj) func testCharge(c chargeable.Chargeable, charge *chargeable.ChargeObject) { res, err := c.Charge(charge) if err != nil { c.HandleErr(err) } fmt.Print(string(res)) } </code></pre></pre>ChristophBerger: <pre><p>I believe the problem is not the type assertion itself but the fact that the type <code>stripe.Currency</code> is different from the type <code>string</code>, although it has the same underlying type. So if the interface object has the dynamic type &#34;string&#34; (after assigning &#34;usd&#34; to it), it cannot be asserted to be a StripeCurrency. </p> <p>According to the <a href="http://gopl.io">GOPL book</a> (section 2.5 on page 39), the reason for this is that a type declaration like <code>type Currency string</code> provides &#34;a way to separate different and perhaps incompatible uses of the underlying type so that they can&#39;t be mixed unintentionally.&#34;</p> <p>Hence it would seem that if the interface variable Currency contains a string, you would need to first type-assert it to a string and then convert the string to a stripe.Currency, like:</p> <pre><code>str, ok := obj.Currency.(string) // test ok stripe := stripe.Currency(string) </code></pre> <p>Working code here: <a href="https://play.golang.org/p/JOAZ0V6Wym">https://play.golang.org/p/JOAZ0V6Wym</a></p> <p>And about type assertion versus conversion:</p> <p>here: <a href="https://golang.org/ref/spec#Type_assertions">https://golang.org/ref/spec#Type_assertions</a></p> <p>and here: <a href="https://golang.org/ref/spec#Conversions">https://golang.org/ref/spec#Conversions</a></p></pre>ChristophBerger: <pre><blockquote> <p>So Currency needs to be flexible on type.</p> </blockquote> <p>What if you make your Currency a string and convert to and from other currency types on the fly? I guess there will not be many different ways of expressing a currency, and none that could not easily be converted to and from a string value.</p> <p>This way you would save yourself from having to mess around with empty interfaces and type conversions.</p></pre>natdm: <pre><p>How can I do that? I read that you can convert from an interface to something, but it&#39;s harder to convert from a string. When Currency was a string instead of interface{}, the error that the left hand was a string and not an interface type.</p></pre>ChristophBerger: <pre><p>What I meant is that if stripe.Currency is a string any obj.Currency is a string, then you can assign rather directly (with a conversion like <code>stripeCurr := stripe.Currency(obj.Currency)</code>.</p> <p>And when a new currency comes along, say <code>type PayPalCurrency int</code>, you can write a conversion function based on PayPal&#39;s list of currency integer values. (Disclaimer: I have no idea how PP declares their currencies)</p></pre>natdm: <pre><p>Ah jeez. It&#39;s so much simpler than I was making it. That worked. </p> <p>Thanks so much, man.</p></pre>: <pre><p>[deleted]</p></pre>natdm: <pre><p>Did you read the entire post?</p> <blockquote> <p>If you&#39;re wondering why I&#39;m not just using stripe.Currency instead of interface...</p> </blockquote></pre>: <pre><p>[deleted]</p></pre>natdm: <pre><p>Declaring a type within a struct as an empty interface isn&#39;t about methods at all.</p></pre>: <pre><p>[deleted]</p></pre>natdm: <pre><p>Currency isn&#39;t my type. Thanks for the help though, it&#39;s resolved. :-)</p></pre>

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

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