«Абстрактный» метод конструктора, переданный в качестве аргумента в Golang

#go #inheritance #interface

#Вперед #наследование #интерфейс

Вопрос:

Как человеку, который освоился в мире Python, мне недавно пришлось улучшить производительность API. Из личных интересов я хотел переделать все это с помощью Golang.

Одна часть реализации состоит из преобразования координат в геометрию GeoJSON и создания из них коллекции.

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

 // This is what I want to create
type Collection struct {
    Geometries *[]Geometry
}

type Geometry interface {}

type Point struct {
    Coordinates [1][2]float64
}

type Polygon struct {
    Coordinates [1][5][2]float64
}

type GeometryConstructor func(float64, float64) *Geometry

// This is the method to convert 
func DataFrameToCollection(data DataFrame, constructor GeometryConstructor) *Collection {
    geometries := make([]Geometry, data.Len())
    for i := 0; i < data.Len(); i   {
        geometries[i] = *constructor(data.Lat.ItemAt(i), data.Lng.ItemAt(i))
    }
    return amp;Collection{
        Geometries: amp;geometries,
    }
}

// This is a constructor method I want to pass
func PointFromLatLng(lat, lng float64) *Point {
    return amp;Point{
        Coordinates: [1][2]float64{
            {lng, lat},
        },
    }
}
  

Поэтому я мог бы в конечном итоге просто подключить соответствующий метод конструктора следующим образом

 func main() {
    // data := ...
    collection := DataFrameToCollection(amp;data, PointFromLatLng)
}
  

Проблема в том, что методы конструктора не возвращают экземпляр интерфейса.

Каков наиболее подходящий идиоматический способ решения этой проблемы (избегая операторов if / switch-case)?

Ответ №1:

Вы можете использовать встроенные адаптеры:

     collection := DataFrameToCollection(amp;data, func(lat,lon float64) Geometry { return PointFromLatLng(lat,lon) } )