wrote a program that converts metrics. Want to expand, need advice

polaris · · 768 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hey there! Right now it only converts fahrenheit to celsius, and celsius to fahrenheit, but i want to expand it to work with other temperature metrics, and eventually to other types of metrics, like weight, length, etc. here&#39;s what I have so far. My main question is how I can tell what metric needs to be converted, and what it needs to be converted to, without a long if/else if or case/when statement. Here&#39;s what I have so far:</p> <pre><code>package main import ( &#34;fmt&#34; &#34;os&#34; &#34;strconv&#34; ) //fahrenheit to celsius func fahrToCels(c int) int { return (c - 32) * (9 / 5) } //celsius to fahrenheit func celsToFahr(f int) int { return (f * (9 / 5)) + 32 } func main() { stemp, _ := strconv.Atoi(os.Args[1]) if os.Args[2] == &#34;c&#34; { fmt.Println(fahrToCels(stemp), &#34;° Celcius&#34;) } else { fmt.Println(celsToFahr(stemp), &#34;° Fahrenheit&#34;) } } </code></pre> <p>Let me know if any ideas jump out. Thanks!</p> <p>I am a beginner with Go. </p> <hr/>**评论:**<br/><br/>mwholt: <pre><p>Welcome to Go!</p> <p>Try using a <code>map[string]func(int)int</code>. Then you just do a map lookup to get the right function for the unit the user wants to convert.</p> <p>I&#39;d also recommend that for your program you use float64 instead of int, since int only has whole number precision. Probably not good enough for most conversion tasks.</p> <p>Unrelated to your question but important advice nonetheless: <code>go fmt</code> your code. (That&#39;s not a rude thing to say around these parts.) Always go fmt all your Go code. It&#39;s not an overstatement. Even better, get a Go plugin for your editor to go fmt your code automatically when you save.</p> <p>Also, and probably more important: Don&#39;t ignore errors. Ever. Actually, this is only true 99% of the time. But in your case, it is not the 1% - so replace <code>stemp, _ := strconv.Atoi(...)</code> with <code>stemp, err := strconv.Atoi(...)</code> and check the error and handle it. <em>Especially</em> since you&#39;re parsing user input!</p></pre>Spirit_of_Stallman: <pre><p>You need use <a href="http://golang.org/pkg/flag/">flags</a>, or build some user interface (command-line, gui, web-interface, etc).</p></pre>kodemizer: <pre><p>This is a great idea.</p> <p>Three recommendations:</p> <ol> <li><p>Use full function names. Such as CelciusToFarenheit or MetersToMiles etc. You are going to have a <em>lot</em> of functions, and if you take shortcuts with the naming then users will have a hard time guessing the proper function name and will have to go back and look it up all the time. If you consistently use the long-form then I can just use PoundsToKilgrams or YearsToMilliseconds without thinking about it.</p></li> <li><p>Use floats by default and provide an Int function. For example CelciusToFarenheit(c float) and CelciusToFarenheitInt(c int). </p></li> <li><p>Make it a library, but also make it a command line utility (perhaps called convertunits). How cool would it be to be able to go type this in bash:. convertunits &#34;10000 meters to parsecs&#34;. </p></li> </ol></pre>ZZ9ZA: <pre><p>Better: Pick one canonical unit for each type, and only write conversion to/from that. \</p> <p>Even better: Have a data table of conversion factors, and only write one function + whatever helpers you need.</p></pre>jerf: <pre><pre><code>$ units 10000m parsecs\; 3.2407793e-13 parsecs </code></pre> <p>Admittedly, the syntax on this old program was dodgier than I was hoping and the documentation, per GNU standards for obscure programs, might as well not have existed.</p></pre>kodemizer: <pre><p>Yeah, I knew that one existed, but it seems in desperate need of a re-write. </p></pre>jerf: <pre><p>Generally, when scaling this sort of thing, you want to have an underlying &#34;canonical&#34; temperature type. You convert everything coming in, and convert when the user asks for a temperature, but internally everything is always in the same format.</p> <pre><code>package temperature type Temperature struct { kelvin float64 // note you can&#39;t get away with int here } func FromKelvin(t float64) Temperature { return Temperature{t} } func FromCelsius(t float64) Temperature { return Temperature{t - 273.15} } func (t Temperature) Celcius float64 { return t.kelvin + 273.15 } func (t Temperature) Kelvin float64 { return t.kelvin } </code></pre> <p>Another approach that can work is:</p> <pre><code>type Temperature interface { Kelvin() Kelvin } type Kelvin float64 func (k Kelvin) Kelvin() Kelvin { return k } func (k Kelvin) Celsius() Celsius { return Celsius(float64(Kelvin) + 273.15) } // rest of the various output formats here type Celsius float64 func (c Celsius) Kelvin() Kelvin { return Kelvin(float64(c) - 273.15) } // no other methods here </code></pre> <p>The first is generally better if you really don&#39;t care about the unit a temperature is in, you just care about the heat content it represents. I&#39;d go with the second if I do want to care about what unit and retain that a Celsius measurement is Celsius for some reason. In this <em>particular</em> case I&#39;d worry that was a code smell (values don&#39;t <em>really</em> depend on what unit they&#39;re measured in, do they? Are you <em>sure</em>?), but I thought it worth showing the general pattern because sometimes it is a better solution.</p></pre>kurin: <pre><p><code>type Temperature float64</code></p></pre>skerpwr: <pre><p><code>(f * (9 / 5)) + 32</code> is equivalent to <code>f + 32</code> thanks to integer precision. <code>(f * (9.0 / 5)) + 32</code> is what you want. </p> <p>Please take a look at <a href="https://golang.org/ref/spec#Constant_expressions" rel="nofollow">https://golang.org/ref/spec#Constant_expressions</a></p> <p>EDIT: To get you thinking like a go developer, I created an abstraction of the conversion functions that I believe answers your question. </p> <p>You could create a map of functions like so:</p> <pre><code>type conversion func (int) int </code></pre> <p>...</p> <pre><code>// Declare two maps var conversions = map[string]conversion { &#34;f2c&#34;: fahrToCels, // functions are values &#34;c2f&#34;: celsToFahr, // ... } var scales = map[string]string { &#34;f2c&#34;: &#34;Celcius&#34;, &#34;c2f&#34;: &#34;Fahrenheit&#34;, // ... } </code></pre> <p>...</p> <pre><code>// Within main stemp, _ := strconv.Atoi(os.Args[1]) // I hope you check the error. convert, validInput := conversions[os.Args[2]] if validInput { scale, _ := scales[os.Args[2]] fmt.Printf(&#34;%d° %s\n&#34;, convert(stemp), scale) } else { // Do something when invalid. } </code></pre></pre>fr4nk3n: <pre><p>Write some <a href="http://golang.org/pkg/testing/" rel="nofollow">tests</a> that covers your convert functions. </p></pre>egonelbre: <pre><p>I would probably start with a value/unit types <a href="https://play.golang.org/p/p0mXBhRPFd" rel="nofollow">https://play.golang.org/p/p0mXBhRPFd</a>. Although it doesn&#39;t solve your conversion problem directly :P.</p></pre>

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

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