<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'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's what I have so far:</p>
<pre><code>package main
import (
"fmt"
"os"
"strconv"
)
//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] == "c" {
fmt.Println(fahrToCels(stemp), "° Celcius")
} else {
fmt.Println(celsToFahr(stemp), "° Fahrenheit")
}
}
</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'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's not a rude thing to say around these parts.) Always go fmt all your Go code. It'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'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'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 "10000 meters to parsecs". </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 "canonical" 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'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't care about the unit a temperature is in, you just care about the heat content it represents. I'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'd worry that was a code smell (values don't <em>really</em> depend on what unit they'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 {
"f2c": fahrToCels, // functions are values
"c2f": celsToFahr,
// ...
}
var scales = map[string]string {
"f2c": "Celcius",
"c2f": "Fahrenheit",
// ...
}
</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("%d° %s\n", 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't solve your conversion problem directly :P.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传