Пакеты, тестирование, файлы и JSON

Собственные пакеты: структура папок, exported и unexported имена

Содержание курса

Конвертер расстояний по пакетам

Навигаторы, логисты и путешественники нередко сталкиваются с тем, что расстояния в разных контекстах выражаются по-разному: дорожные карты оперируют километрами, американские маршруты — милями, а морские и авиационные карты — узлами и морскими милями. Перевод вручную неудобен и легко приводит к ошибкам, поэтому разумно вынести все формульные знания в одно место и обращаться к ним через чёткий интерфейс.

Именно так устроена эта программа: логика пересчёта живёт в отдельном пакете, который отвечает за всё, что связано с коэффициентами и вычислениями, но не выставляет их наружу напрямую. Внешний мир видит только готовые функции-преобразователи, не имея доступа к внутренним константам. Такое разделение позволяет поддерживать чистоту границ между тем, что программа умеет делать, и тем, как именно она это делает.

Точка запуска принимает одно расстояние и, обратившись к пакету, получает его значения сразу в нескольких единицах измерения. Результаты выводятся в строго определённом порядке — так, чтобы пользователь мог одним взглядом сравнить все три величины и выбрать нужную для своего маршрута или документа.

Что нужно сделать

Допишите две экспортируемые функции пакета distance: KilometersToMiles и KilometersToNauticalMiles. Коэффициенты уже объявлены внутри пакета и должны остаться неэкспортируемыми. Публичные тесты импортируют пакет по полному пути модуля и проверяют нулевое, единичное и дробное расстояние.

О данных в ответах

Используйте учебные данные. Не вставляйте пароли, токены, ключи доступа, паспортные и банковские данные, а также персональные данные других людей. Политика обработки данных.

Проверяется тестами (2)
  • Public go test ./...
  • health
    GET /health200
Go-проект · distance/convert.go

Сначала выполняется go test ./..., затем сервис собирается и проверяется HTTP-запросами. Внешняя сеть и скачивание модулей отключены.

distance/convert_test.go
package distance_test

import (
    "math"
    "testing"
    "latorn.local/golang/retrofit/lesson_20/distance"
)

func closeTo(a, b float64) bool { return math.Abs(a-b) < 1e-9 }
func TestConversions(t *testing.T) {
    cases := []struct{name string; in, miles, nautical float64}{
        {"zero", 0, 0, 0}, {"one", 1, 0.621371, 0.539957}, {"route", 42.5, 26.4082675, 22.9481725},
    }
    for _, tc := range cases { t.Run(tc.name, func(t *testing.T) {
        if got := distance.KilometersToMiles(tc.in); !closeTo(got, tc.miles) { t.Errorf("miles=%v want=%v", got, tc.miles) }
        if got := distance.KilometersToNauticalMiles(tc.in); !closeTo(got, tc.nautical) { t.Errorf("nautical=%v want=%v", got, tc.nautical) }
    }) }
}
main.go
package main

import (
    "io"
    "log"
    "net/http"
    "latorn.local/golang/retrofit/lesson_20/distance"
)

func main() {
    _ = distance.KilometersToMiles(1)
    mux := http.NewServeMux()
    mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/plain; charset=utf-8")
        w.WriteHeader(http.StatusOK)
        _, _ = io.WriteString(w, "ok\n")
    })
    if err := http.ListenAndServe(":18080", mux); err != nil {
        log.Fatal(err)
    }
}
cmd/convert/main.go
package main

import (
    "fmt"
    "io"
    "os"

    "latorn.local/golang/retrofit/lesson_20/distance"
)

func run(in io.Reader, out io.Writer) error {
    var km float64
    if _, err := fmt.Fscan(in, &km); err != nil { return err }
    _, err := fmt.Fprintf(out, "kilometers=%.3f\nmiles=%.6f\nnautical_miles=%.6f\n", km, distance.KilometersToMiles(km), distance.KilometersToNauticalMiles(km))
    return err
}

func main() {
    if err := run(os.Stdin, os.Stdout); err != nil { fmt.Fprintln(os.Stderr, err) }
}
cmd/convert/main_test.go
package main

import (
    "bytes"
    "strings"
    "testing"
)

func TestRun(t *testing.T) {
    var out bytes.Buffer
    if err := run(strings.NewReader("42.5\n"), &out); err != nil { t.Fatal(err) }
    want := "kilometers=42.500\nmiles=26.408268\nnautical_miles=22.948173\n"
    if out.String() != want { t.Fatalf("output=%q want=%q", out.String(), want) }
}
РешениеGo · Go 1.27 (Modal)

Отправьте решение, чтобы увидеть результаты тестов.