Swift 泛型 *= 操作错误

Swift generics *= operator error

我有以下简单的结构类型。

import Foundation
import SceneKit

protocol Named {
    class var name: String { get }
}

extension Float: Named {
    static var name: String { return "Float" }
}

struct Vector3<T: protocol<Named, FloatingPointType>>: Printable { // This protocol solves the generics issue
    // Properties
    var x, y, z: T
    var description: String {
        return "Vector3<\(T.name)>(\(x), \(y), \(z))"
    }
    // Methods - mutating
    mutating func factored(factor: T) {
        x *= factor
    }

}

我希望能够将创建结构时使用的相同类型作为 factored 的参数。但这会导致 Cannot invoke *= with an argument list of type (T, T).

我是否需要实现 *= 运算符以及我最终需要的任何其他运算符?我该怎么做?

编辑

在@matt 提出建议将 Vector3 声明为遵守 FloatingPointType 协议后,问题就解决了。虽然现在我在 factored 方法中得到一个 T is not identical to UInt8

这不会编译,因为不能保证您的 T 类型可以相乘,甚至可以分配。您必须 implement/override 命名类型的 = 和 * 运算符才能使其工作。不过,我不确定协议是否甚至可以要求执行运算符。

更新答案

根据@matt 的建议,在这里组合协议可能最有意义:

protocol NamedAndMultipliable {
    class var name: String { get }
    func *=(inout lhs: Self, rhs: Self)
}

func *=(inout lhs: Int, rhs: Int) {
    lhs = lhs * rhs
}

extension Int : NamedAndMultipliable {
    static var name: String { return "Int" }
}
extension Double : NamedAndMultipliable {
    static var name: String { return "Double" }
}
extension Float : NamedAndMultipliable {
    static var name: String { return "Float" }
}

struct Vector3<T: NamedAndMultipliable>: Printable {
    // Properties
    var x, y, z: T
    var description: String {
        return "Vector3<\(T.name)>(\(x), \(y), \(z))"
    }
    // Methods - mutating
    mutating func factored(factor: T) {
        x *= factor
    }   
}

原答案

通过执行以下操作,我得到了我认为您想要的结果:

protocol Named {
    class var name: String { get }
}

protocol Multipliable {
    func *(lhs: Self, rhs: Self) -> Self
}

extension Int : Multipliable {}
extension Double : Multipliable {}
extension Float : Multipliable {}

extension Int : Named {
    static var name: String { return "Int" }
}
extension Double : Named {
    static var name: String { return "Double" }
}
extension Float : Named {
    static var name: String { return "Float" }
}

struct Vector3<T: protocol<Named, Multipliable>>: Printable {
    // Properties
    var x, y, z: T
    var description: String {
        return "Vector3<\(T.name)>(\(x), \(y), \(z))"
    }
    // Methods - mutating
    mutating func factored(factor: T) {
        x = x * factor
    }

}

如果您更喜欢使用 *= 运算符,可以这样做,但如果您也想支持 Int,则需要为其添加一个函数。

protocol MultipliableIntoSelf {
    func *=(inout lhs: Self, rhs: Self)
}

func *=(inout lhs: Int, rhs: Int) {
    lhs = lhs * rhs
}

extension Int : MultipliableIntoSelf {}
extension Double : MultipliableIntoSelf {}
extension Float : MultipliableIntoSelf {}

protocol Named {
    class var name: String { get }
}

extension Int : Named {
    static var name: String { return "Int" }
}
extension Double : Named {
    static var name: String { return "Double" }
}
extension Float : Named {
    static var name: String { return "Float" }
}

struct Vector3<T: protocol<Named, MultipliableIntoSelf>>: Printable {
    // Properties
    var x, y, z: T
    var description: String {
        return "Vector3<\(T.name)>(\(x), \(y), \(z))"
    }
    // Methods - mutating
    mutating func factored(factor: T) {
        x *= factor
    }

}