Problem statement:
Write a program that converts all given temperatures from a given input temperature scale to a given output temperature scale. The temperature scales to be supported are Kelvin, Celsius, Fahrenheit, Rankine, Delisle, Newton, Rømer, Réaumur.
Synopsis: tempconv INPUT_SCALE OUTPUT_SCALE [TEMPERATURE]...
The INPUT_SCALE
and OUTPUT_SCALE
shall be given as follows:
K
for KelvinC
for CelsiusF
for FahrenheitR
for RankineD
for DelisleN
for NewtonRø
for RømerRé
for Réaumur.
Example:
tempconv K C 0 273.15 373.15
-273.15
0.0
100.0
My solution in Golang:
package main
import (
"fmt"
"os"
"strconv"
)
type TempConv struct {
toKelvin func(other float64) float64
fromKelvin func(kelvin float64) float64
}
var scales = map[string]TempConv{}
func init() {
register := func(toKelvin func(other float64) float64, fromKelvin func(kelvin float64) float64, names []string) {
conv := TempConv{toKelvin, fromKelvin};
for _, name := range names {
scales[name] = conv
}
}
register(func(celsius float64) float64 { return celsius + 273.15 }, func(kelvin float64) float64 { return kelvin - 273.15 }, []string{"°C", "C", "c"});
register(func(kelvin float64) float64 { return kelvin }, func(kelvin float64) float64 { return kelvin }, []string{"K"});
register(func(fahrenheit float64) float64 { return (fahrenheit + 459.67) * 5 / 9 }, func(kelvin float64) float64 { return kelvin * 9 / 5 - 459.67 }, []string{"°F", "F", "f"});
register(func(delisle float64) float64 { return 373.15 - delisle * 2 / 3 }, func(kelvin float64) float64 { return (373.15 - kelvin) * 3 / 2 }, []string{"°De", "De", "DE", "de"});
register(func(newton float64) float64 { return newton*100/33 + 273.15 }, func(kelvin float64) float64 { return (kelvin - 273.15) * 33 / 100 }, []string{"°N", "N", "n"});
register(func(rankine float64) float64 { return rankine * 5 / 9 }, func(kelvin float64) float64 { return kelvin * 9 / 5 }, []string{"°R", "R", "r"});
register(func(réaumur float64) float64 { return réaumur * 5 / 4 + 273.15 }, func(kelvin float64) float64 { return (kelvin - 273.15) * 4 / 5 }, []string{"°Ré", "°Re", "Ré", "RÉ", "ré", "Re", "RE", "re"});
register(func(rømer float64) float64 { return (rømer - 7.5) * 40 / 21 + 273.15 }, func(kelvin float64) float64 { return (kelvin-273.15) * 21 / 40 + 7.5 }, []string{"°Rø", "°Ro", "Rø", "RØ", "rø", "Ro", "RO", "ro"});
}
func main() {
toKelvin := scales[os.Args[1]].toKelvin
fromKelvin := scales[os.Args[2]].fromKelvin
for _, arg := range os.Args[3:] {
inputTemp, _ := strconv.ParseFloat(arg, 64)
fmt.Println(fromKelvin(toKelvin(inputTemp)))
}
}
I'm aware that error handling is incomplete.
I'm particularly interested in the following feedback:
- Is there a smarter way to initialize
scales
without requiring aninit()
function? - Is there a way to make the calls to
register()
shorter? I know golang doesn't have a terse lambda syntax with->
or=>
(or has it?), but maybe there's another way?