Swift,结构。如何简化 struct multiple 属性 .dot 访问器?
Swift, struct. How to simplify struct multiple property .dot accessors?
我有一些表示地球上位置的结构,表示一个简单的 lat/lon 位置(Point2D
), lat/lon/height location (Point3D
), 以及机场等命名位置 姓名/lat/lon/身高位置(Airport
).
struct Point2D {
var lat: Double
var lon: Double
}
struct Point3D {
var point2D: Point2D
var height_m: Double
}
struct Airport {
var name: String
var point3D: Point3D
}
这些结构按层次结构使用,效果很好,但在从机场实例中获取数据时确实会导致一些长的 .dot 访问。比如获取机场的纬度值是airport.point3D.point2D.lat
,不太理想。
let airportLHR1 = Airport(name: "LHR", point3D: Point3D(point2D: Point2D(lat: 51.5, lon: -0.5), height_m: 25.0))
print("Airport: \(airportLHR1.name). Lat,Lon: \(airportLHR1.point3D.point2D.lat), \(airportLHR1.point3D.point2D.lon)")
// --> Airport: LHR. Lat,Lon: 51.5, -0.5
我已经将机场结构重构为 'flatten' 属性 .dot 访问,但我觉得可能有更好的方法来实现这一点。
struct Airport2 {
var name: String
private var _point3D: Point3D
var lat: Double { get { _point3D.point2D.lat } set { _point3D.point2D.lat = newValue } }
var lon: Double { get { _point3D.point2D.lon } set { _point3D.point2D.lon = newValue } }
var height_m: Double { get { _point3D.height_m } set { _point3D.height_m = newValue } }
init(name: String, lat: Double, lon: Double, height_m: Double) {
self.name = name
self._point3D = Point3D(point2D: Point2D(lat: lat, lon: lon), height_m: height_m)
}
}
现在访问机场的数据要简单得多...
let airportLHR2 = Airport2(name: "LHR", lat: 51.5, lon: -0.5, height_m: 25.0)
print("Airport: \(airportLHR2.name). Lat,Lon: \(airportLHR2.lat), \(airportLHR2.lon)")
// --> Airport: LHR. Lat,Lon: 51.5, -0.5
...但是有更好的方法吗?
假设您用 height
表示高度,您可以简单地使用 CLLocation
,并可选择使用便利初始化程序扩展它,让生活更轻松。
extension CLLocation {
convenience init(lat: CLLocationDegrees, lon: CLLocationDegrees, alt: CLLocationDistance) {
self.init(coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon),
altitude: alt,
horizontalAccuracy: 0,
verticalAccuracy: 0,
timestamp: .now)
}
}
struct Airport {
let name: String
let loc: CLLocation
}
let lax = Airport(name: "LAX", loc: CLLocation(lat: 33.9416, lon: -118.4085, alt: 39.0144))
print(lax.loc.coordinate.longitude) // -118.4085
print(lax.loc.altitude) // 39.0144
我建议:
struct Coordinate {
let latitude: Double
let longitude: Double
}
struct Location {
let coordinate: Coordinate
let altitude: Double
}
struct Airport {
let name: String
let location: Location
}
extension Airport {
var latitude: Double { location.coordinate.latitude }
var longitude: Double { location.coordinate.longitude }
}
以上,遵循最佳实践,我赞成不变性。但是如果你真的需要可变性:
struct Coordinate {
var latitude: Double
var longitude: Double
}
struct Location {
var coordinate: Coordinate
var altitude: Double
}
struct Airport {
var name: String
var location: Location
}
extension Airport {
var latitude: Double {
get { location.coordinate.latitude }
set { location.coordinate.latitude = newValue }
}
var longitude: Double {
get { location.coordinate.longitude }
set { location.coordinate.longitude = newValue }
}
}
无关,但我可能会将这些计算属性移动到 Place
协议中:
protocol Place {
var name: String { get }
var location: Location { get }
}
extension Place {
var latitude: Double { location.coordinate.latitude }
var longitude: Double { location.coordinate.longitude }
}
struct Airport: Place {
let name: String
let location: Location
}
这样您也可以定义机场以外的地方,而不必重复这些计算属性。
我有一些表示地球上位置的结构,表示一个简单的 lat/lon 位置(Point2D
), lat/lon/height location (Point3D
), 以及机场等命名位置 姓名/lat/lon/身高位置(Airport
).
struct Point2D {
var lat: Double
var lon: Double
}
struct Point3D {
var point2D: Point2D
var height_m: Double
}
struct Airport {
var name: String
var point3D: Point3D
}
这些结构按层次结构使用,效果很好,但在从机场实例中获取数据时确实会导致一些长的 .dot 访问。比如获取机场的纬度值是airport.point3D.point2D.lat
,不太理想。
let airportLHR1 = Airport(name: "LHR", point3D: Point3D(point2D: Point2D(lat: 51.5, lon: -0.5), height_m: 25.0))
print("Airport: \(airportLHR1.name). Lat,Lon: \(airportLHR1.point3D.point2D.lat), \(airportLHR1.point3D.point2D.lon)")
// --> Airport: LHR. Lat,Lon: 51.5, -0.5
我已经将机场结构重构为 'flatten' 属性 .dot 访问,但我觉得可能有更好的方法来实现这一点。
struct Airport2 {
var name: String
private var _point3D: Point3D
var lat: Double { get { _point3D.point2D.lat } set { _point3D.point2D.lat = newValue } }
var lon: Double { get { _point3D.point2D.lon } set { _point3D.point2D.lon = newValue } }
var height_m: Double { get { _point3D.height_m } set { _point3D.height_m = newValue } }
init(name: String, lat: Double, lon: Double, height_m: Double) {
self.name = name
self._point3D = Point3D(point2D: Point2D(lat: lat, lon: lon), height_m: height_m)
}
}
现在访问机场的数据要简单得多...
let airportLHR2 = Airport2(name: "LHR", lat: 51.5, lon: -0.5, height_m: 25.0)
print("Airport: \(airportLHR2.name). Lat,Lon: \(airportLHR2.lat), \(airportLHR2.lon)")
// --> Airport: LHR. Lat,Lon: 51.5, -0.5
...但是有更好的方法吗?
假设您用 height
表示高度,您可以简单地使用 CLLocation
,并可选择使用便利初始化程序扩展它,让生活更轻松。
extension CLLocation {
convenience init(lat: CLLocationDegrees, lon: CLLocationDegrees, alt: CLLocationDistance) {
self.init(coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon),
altitude: alt,
horizontalAccuracy: 0,
verticalAccuracy: 0,
timestamp: .now)
}
}
struct Airport {
let name: String
let loc: CLLocation
}
let lax = Airport(name: "LAX", loc: CLLocation(lat: 33.9416, lon: -118.4085, alt: 39.0144))
print(lax.loc.coordinate.longitude) // -118.4085
print(lax.loc.altitude) // 39.0144
我建议:
struct Coordinate {
let latitude: Double
let longitude: Double
}
struct Location {
let coordinate: Coordinate
let altitude: Double
}
struct Airport {
let name: String
let location: Location
}
extension Airport {
var latitude: Double { location.coordinate.latitude }
var longitude: Double { location.coordinate.longitude }
}
以上,遵循最佳实践,我赞成不变性。但是如果你真的需要可变性:
struct Coordinate {
var latitude: Double
var longitude: Double
}
struct Location {
var coordinate: Coordinate
var altitude: Double
}
struct Airport {
var name: String
var location: Location
}
extension Airport {
var latitude: Double {
get { location.coordinate.latitude }
set { location.coordinate.latitude = newValue }
}
var longitude: Double {
get { location.coordinate.longitude }
set { location.coordinate.longitude = newValue }
}
}
无关,但我可能会将这些计算属性移动到 Place
协议中:
protocol Place {
var name: String { get }
var location: Location { get }
}
extension Place {
var latitude: Double { location.coordinate.latitude }
var longitude: Double { location.coordinate.longitude }
}
struct Airport: Place {
let name: String
let location: Location
}
这样您也可以定义机场以外的地方,而不必重复这些计算属性。