[英]Generic class of generic class with one argument/parameter
I have this syntactical issue with my data structure.我的数据结构存在语法问题。 What makes it worse is that I can not talk about it in detail.
更糟糕的是我不能详细谈论它。 The company I am employed at operates in the public transportation sector and I am under NDA and boss would kill me if I posted anything too specific.
我受雇的公司在公共交通部门运营,我在保密协议下,如果我发布任何太具体的内容,老板会杀了我。 I hope you understand!
我希望你明白!
I have this perfect example though.我有这个完美的例子。 There are no inconsistencies at all;) Well, okay, there are.
根本没有不一致;)好吧,有。 However I am convinced that most of you out there are smart enough to get what is of importance here.
然而,我相信你们中的大多数人都足够聪明,可以得到这里重要的东西。
Basic structure:基本结构:
class Propulsion {
var horsePower: Double
init(horsePower: Double) {
self.horsePower = horsePower
}
static let pedes = Propulsion(horsePower: 0.2)
}
class Motor: Propulsion {
var range: Double
init(range: Double, horsePower: Double) {
self.range = range
super.init(horsePower: horsePower)
}
static let otto = Motor(range: 1000, horsePower: 100)
static let electric = Motor(range: 400, horsePower: 200)
}
class Vehicle<P: Propulsion> {
var propulsion: P
init(propulsion: P) {
self.propulsion = propulsion
}
}
class Bicycle<P: Propulsion>: Vehicle<P> {
var hasFrontSuspension: Bool
init(hasFrontSuspension: Bool, propulsion: P) {
self.hasFrontSuspension = hasFrontSuspension
super.init(propulsion: propulsion)
}
}
class Car<P: Propulsion>: Vehicle<P> {
func rangePerHorsePower() -> Double where P: Motor {
propulsion.range / propulsion.horsePower
}
}
Now I would like to declare a parking spot for a car.现在我想申报一个汽车停车位。 Like so:
像这样:
var carParkingSpot: ParkingSpot<Car<Motor>>
For the class ParkingSpot
I have some class like this in mind:对于 class
ParkingSpot
,我有一些像这样的 class:
class ParkingSpot<V: Vehicle<P>> where P: Propulsion {
var vehicle: Vehicle<P>
init(vehicle: Vehicle<P>) {
self.vehicle = vehicle
}
func taxForRange() -> Double where P: Motor {
vehicle.propulsion.range * 50
}
}
From the last bit I get back a bunch of从最后一点我得到了一堆
Cannot find type 'P' in scope
在 scope 中找不到类型“P”
This one doesn't work either:这个也不起作用:
class ParkingSpot<V: Vehicle<P: Propulsion>>
Expected '>' to complete generic argument list
期望“>”来完成通用参数列表
This implementation works though:这个实现虽然有效:
class ParkingSpot<V: Vehicle<P>, P: Propulsion> {
var vehicle: Vehicle<P>
init(vehicle: Vehicle<P>) {
self.vehicle = vehicle
}
func taxForRange() -> Double where P: Motor {
vehicle.propulsion.range * 50
}
}
However I don't want to duplicate the Motor
bit:但是我不想复制
Motor
位:
var carParkingSpot: ParkingSpot<Car<Motor>, Motor>
How can I accomplish this with just one generic parameter?如何仅使用一个通用参数来完成此操作?
You may use the "Protocol oriented" approach:您可以使用“面向协议”的方法:
protocol PropulsionP {
var horsePower: Double { get }
}
protocol MotorP: PropulsionP {
var range: Double { get }
}
struct MotorS: MotorP {
var range: Double
var horsePower: Double
init(range: Double, horsePower: Double) {
self.range = range
self.horsePower = horsePower
}
}
protocol VehicleP {
associatedtype P: PropulsionP
var propulsion: P { get }
}
struct BicycleS<Prop: PropulsionP>: VehicleP {
let hasFrontSuspension: Bool
var propulsion: Prop
init(
hasFrontSuspension: Bool,
propulsion: Prop
) {
self.hasFrontSuspension = hasFrontSuspension
self.propulsion = propulsion
}
}
struct CarS<Prop: PropulsionP>: VehicleP {
var propulsion: Prop
func rangePerHorsePower() -> Double where P: MotorP {
propulsion.range / propulsion.horsePower
}
}
struct ParkingSpotS<V: VehicleP> {
var vehicle: V
init(vehicle: V) {
self.vehicle = vehicle
}
func taxForRange() -> Double where V.P: MotorP {
vehicle.propulsion.range * 50
}
}
var carParkingSpot: ParkingSpotS<CarS<MotorS>>
No double MotorS
bit.无双
MotorS
钻头。 Quod erat demonstrandum. Quod erat demonstrandum。
I used the somewhat unusual naming to emphasize the point.我使用了有点不寻常的命名来强调这一点。
(needed to make some edit, erronously typed Motor
where I actually need MotorP
) (需要进行一些编辑,在我实际需要
MotorP
的地方输入错误的Motor
)
Update更新
I was on the road with my preferred car and tried it out:我开着我喜欢的车在路上试了一下:
var carParkingSpot: ParkingSpotS<CarS<MotorS>> = .init(
vehicle: .init(
propulsion: .init(
range: 760,
horsePower: 240
)
)
)
print(carParkingSpot.taxForRange())
38000.0
Alternatively you can use this initialiser:或者,您可以使用此初始化程序:
var carParkingSpot: ParkingSpotS = .init(
vehicle: CarS(
propulsion: MotorS(
range: 760,
horsePower: 240
)
)
)
Update更新
Now suppose you are utilising a third party library which already provides a nice implementation of a motor.现在假设您正在使用第三方库,它已经提供了一个很好的电机实现。
What you need to do is to implement an extension for their given class or struct TheirMotor
which conforms to your protocol MotorP
:您需要做的是为他们给定的 class 或符合您的协议
MotorP
的结构TheirMotor
实施扩展:
import FancyMotors
extension TheirMotor: MotorP {
let range: Double {
// calculate `range` in terms of the
// given API of `TheirMotor`:
...
return range
}
}
Then, you can use it like below:然后,您可以像下面这样使用它:
var carParkingSpot: ParkingSpotS = .init(
vehicle: CarS(
propulsion: TheirMotor(
distance: 760,
power: 240
)
)
)
Note, that you use TheirMotor
and need to use the appropriate initialiser to create it.请注意,您使用
TheirMotor
并且需要使用适当的初始化程序来创建它。
This seems to work:这似乎有效:
class ParkingSpot<V: Vehicle<Propulsion>>
{
var vehicle: V
init(vehicle: V)
{
self.vehicle = vehicle
}
func taxForEngineeNoise() -> Double
{
switch vehicle.propulsion
{
case is Motor:
return vehicle.propulsion.horsePower * 50
default:
...
}
}
func taxForRange() -> Double
{
if let motor = vehicle.propulsion as? Motor
{
return motor.range * 50
}
else
{
...
}
}
}
Alternatively, perhaps hide the duplication where you can?或者,也许可以隐藏重复项?
typealias ParkingSpotX = ParkingSpot<Car<Motor>, Motor>
var parkingSpot: ParkingSpotX
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.