Function Swift、数学函数和协议

Function Swift、数学函数和协议,function,math,swift,protocols,Function,Math,Swift,Protocols,我正在尝试创建两个协议arithmaticType和MathematicType,它们将在泛型运算符函数的where子句中使用 protocol ArithmeticType { func +(lhs: Self, rhs: Self) -> Self func -(lhs: Self, rhs: Self) -> Self func *(lhs: Self, rhs: Self) -> Self func /(lhs: Self, rhs: S

我正在尝试创建两个协议arithmaticType和MathematicType,它们将在泛型运算符函数的where子句中使用

protocol ArithmeticType {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
}

extension Int : ArithmeticType {
}

extension Double : ArithmeticType {
}

extension Float : ArithmeticType {
}
算术类型按预期工作,Int、Float和Double都符合它。然而,以下方法失败了

import Darwin

protocol MathematicType {
    func sin(x: Self) -> Self
}

extension Double : MathematicType {
}

extension Float : MathematicType {
}
在操场的控制台输出上,我看到:

Playground execution failed: <EXPR>:35:1: error: type 'Double' does not conform to protocol 'MathematicType'
extension Double : MathematicType {
^
<EXPR>:32:10: note: protocol requires function 'sin' with type 'Double -> Self'
    func sin(x: Self) -> Self
         ^
<EXPR>:39:1: error: type 'Float' does not conform to protocol 'MathematicType'
extension Float : MathematicType {
^
<EXPR>:32:10: note: protocol requires function 'sin' with type 'Float -> Self'
    func sin(x: Self) -> Self
         ^
游乐场执行失败::35:1:错误:类型“Double”与协议“MathematicType”不一致
扩展名双:Mathematic类型{
^
:32:10:注意:协议需要类型为“Double->Self”的函数“sin”
func sin(x:Self)->Self
^
:39:1:错误:类型“Float”不符合协议“MathematicType”
扩展浮点:数学类型{
^
:32:10:注意:协议需要类型为“Float->Self”的函数“sin”
func sin(x:Self)->Self
^
我希望数学函数的行为和上面的运算符一样。有什么办法吗

==编辑:

现在我意识到试图简化我的问题是个坏主意。上下文是这个类(可选值的向量)

类向量{
var数据=[T?]()
init(fromArray:Array){
对于fromArray中的i{
数据追加(一)
}
}
init(){
}
初始化(计数:Int){
因为我在0..T{
让i=索引>0?索引%count():-索引%count()
返回数据[i]
}
}
除此之外,我还为+运算符定义了一个通用函数

func +<T where T: ArithmeticType>(left: Vector<T>, right: Vector<T>) -> Vector<T> {
    let resultCount = max(left.count(),right.count())
    var result = Vector<T>()
    for i in 0..<resultCount {
        if left[i] != nil && right[i] != nil {
            result.append(left[i]!+right[i]!)
        }
        else {
            result.append(nil)
        }
    }
    return result
}
func+(左:向量,右:向量)->Vector{
让resultCount=max(left.count(),right.count())
var结果=向量()
对于0..Vector中的i{
var结果=向量()
对于0..Vector中的i{
var结果=向量()

对于0..中的i,编译器错误是因为您声明了
sin()
作为
MathematicType
协议的方法,然后声明
Double
实现了
MathematicType
,但实际上没有编写
sin()
方法

extension Double {
    func sin(x: Double) -> Double {
        return Darwin.sin(x)
    }
}
但我不认为这是你想要的,是吗?你想写下这个:

let myAngle = 3.14159
let sineValue = myAngle.sin()
如果是这种情况,您的协议和扩展需要如下所示:

protocol MathematicType {
    func sin() -> Self
}

extension Double : MathematicType {
    func sin() -> Double {
        return Darwin.sin(self)
    }
}

您的
MathematicType
协议,以及您在
Float
Double
扩展中对其一致性的声明,表示
Float
Double
应该提供
sin
作为实例方法。也就是说,您应该能够编写如下代码:

let zero = 0.0    // inferred type Double
zero.sin(1.5707963268) // returns about 1.0
请注意,
sin
的调用实际上与
zero
的值无关,因此这可能不是您想要的行为

您可能希望让
sin
成为一个免费函数,因此您可以编写:

sin(1.5707963268)
对吧?

在这种情况下,您的工作已经完成…标准库定义了以下两个方面:

func sin(x: Double) -> Double
func sin(x: Float) -> Float
如果您真正想要的是将
MathematicType
用作一个通用参数,意思是“一个可以取正弦值的类型”,那么您需要一个通用
sin
函数。类似这样的函数(快速kludy解决方案,可能更好):

func正弦(x:T)->T{
如果设v=x为?双{
将sin(v)返回为T
}
如果让v=x作为浮点数{
将sin(v)返回为T
}
fatalError(“未知浮点类型”)
}

(还要注意,
Float
Double
都遵守一个协议,所以我在示例中使用了这个协议。)

我认为问题在于操作员需求和实例方法需求是不同的,尽管它们在语法上看起来相似。操作员总是在全局级别定义的,因此操作员需求是全局级别对操作员的需求。另一方面,实例方法需求是ins的需求实例方法。无法指定全局函数要求。

我认为如果您希望一个类型符合多个协议,应该这样做:
extension Double:MathematicType,arithmaticType{}
你是对的,但是我把它们分开,指出我的问题是你的
func-sin
示例看起来不错,除了它不能调用标准库
sin
而不检查并抛出它的参数——请看我的答案和它的新注释。@rickster我看不到在
func-sin
中检查类型的意义ed有两个专门的
func sin(x:Vector)->Vector
和Float也是一样。在这两种情况下,这对泛型编程来说都是一个很大的限制。我想知道自由函数是故意从泛型编程中漏掉的,还是苹果认为它们没有用。从你的回答中,我了解到在协议括号内我声明了“方法”所以,我仍然不明白的是:1)算术类型方法中的运算符是自由函数吗?我相信它们是自由函数。2)为什么算术运算符和sin函数不同?1.运算符是协议声明的常规规则的例外。您将运算符定义为自由函数(即在全局范围内),但通过在
协议
.2中列出它们,可以使它们成为协议的要求。
sin
不是运算符,并且运算符是唯一可以列为协议要求的自由函数。如果希望函数在多种类型上运行,请编写一个泛型函数。如果希望泛型函数将其泛型参数设置为采用特定类型的标准库函数,您必须检查并强制转换该类型…就像我的答案中的泛型
sine
函数一样。不,我绝对不想要方法,而是需要将sin函数与泛型t一起使用,可以是Float或Double,请参见问题中的编辑。
let zero = 0.0    // inferred type Double
zero.sin(1.5707963268) // returns about 1.0
sin(1.5707963268)
func sin(x: Double) -> Double
func sin(x: Float) -> Float
func sine<T: FloatingPointType>(x: T) -> T {
    if let v = x as? Double {
        return sin(v) as T
    }
    if let v = x as? Float {
        return sin(v) as T
    }
    fatalError("unknown FloatingPointType")
}