<p>I'm working with the stripe library and it has a type of 'Currency' 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("Currency '%v' could not be converted to stripe.Currency.", obj.Currency)
}
</code></pre>
<p>The error I'm getting when I use "usd" as a param:</p>
<pre><code>Other error occurred: Currency 'usd' could not be converted to stripe.Currency.
</code></pre>
<p>This works if I create the struct with stripe.Currency = "usd". Why doesn't it work when I type-assert it?</p>
<p>If you're wondering why I'm not just using stripe.Currency instead of interface, I'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 "usd" as a param? How does this part of the code look like? </p></pre>natdm: <pre><p>Using the string "usd" 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't it be type-asserted to stripe.Currency?</p>
<pre><code> testAcct := stripe.NewStripe(keys)
testChargeObj := &chargeable.ChargeObject{
Amount: 1000,
Desc: "Test Charge card ID card_<id>",
Currency: "usd",
Source: "tok_<tok>",
}
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 "string" (after assigning "usd" 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 "a way to separate different and perhaps incompatible uses of the underlying type so that they can't be mixed unintentionally."</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'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's list of currency integer values. (Disclaimer: I have no idea how PP declares their currencies)</p></pre>natdm: <pre><p>Ah jeez. It'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're wondering why I'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't about methods at all.</p></pre>: <pre><p>[deleted]</p></pre>natdm: <pre><p>Currency isn't my type. Thanks for the help though, it's resolved. :-)</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传