繁体   English   中英

泛型 class 的泛型 class 带有一个参数/参数

[英]Generic class of generic class with one argument/parameter

我的数据结构存在语法问题。 更糟糕的是我不能详细谈论它。 我受雇的公司在公共交通部门运营,我在保密协议下,如果我发布任何太具体的内容,老板会杀了我。 我希望你明白!

我有这个完美的例子。 根本没有不一致;)好吧,有。 然而,我相信你们中的大多数人都足够聪明,可以得到这里重要的东西。

基本结构:

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
    }
}

现在我想申报一个汽车停车位。 像这样:

var carParkingSpot: ParkingSpot<Car<Motor>>

对于 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
    }
}

从最后一点我得到了一堆

在 scope 中找不到类型“P”

这个也不起作用:

class ParkingSpot<V: Vehicle<P: Propulsion>>

期望“>”来完成通用参数列表

这个实现虽然有效:

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
    }
}

但是我不想复制Motor位:

var carParkingSpot: ParkingSpot<Car<Motor>, Motor>

如何仅使用一个通用参数来完成此操作?

您可以使用“面向协议”的方法:

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>>

无双MotorS钻头。 Quod erat demonstrandum。

我使用了有点不寻常的命名来强调这一点。

(需要进行一些编辑,在我实际需要MotorP的地方输入错误的Motor

更新

我开着我喜欢的车在路上试了一下:

var carParkingSpot: ParkingSpotS<CarS<MotorS>> = .init(
    vehicle: .init(
        propulsion: .init(
            range: 760,
            horsePower: 240
        )
    )
)

print(carParkingSpot.taxForRange())
38000.0

或者,您可以使用此初始化程序:

var carParkingSpot: ParkingSpotS = .init(
    vehicle: CarS(
        propulsion: MotorS(
            range: 760,
            horsePower: 240
        )
    )
)

更新

现在假设您正在使用第三方库,它已经提供了一个很好的电机实现。

您需要做的是为他们给定的 class 或符合您的协议MotorP的结构TheirMotor实施扩展

import FancyMotors

extension TheirMotor: MotorP {
    let range: Double {
        // calculate `range` in terms of the 
        // given API of `TheirMotor`:
        ...
        return range
    }
}

然后,您可以像下面这样使用它:

var carParkingSpot: ParkingSpotS = .init(
    vehicle: CarS(
        propulsion: TheirMotor( 
            distance: 760,
            power: 240
        )
    )
)

请注意,您使用TheirMotor并且需要使用适当的初始化程序来创建它。

这似乎有效:

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
        {
            ...
        }
    }
}

或者,也许可以隐藏重复项?

typealias ParkingSpotX = ParkingSpot<Car<Motor>, Motor>

var parkingSpot: ParkingSpotX

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM