Swift泛型函数错误?

时间:2014-12-19 06:47:46

标签: ios xcode swift

这是我的代码:

func swapTwoValues<T>(inout a: T, inout b: T){
  let temp = a
  a = b
  b = temp
}
var aInt = 5
var bInt = 98
swapTwoValues(&aInt, &bInt)

当调用函数swapTwoValues()时,&#34; T&#34;是Int Type

但是当我将此代码更改为

func swapTwoValues<T,S:String>(inout a: T, inout b: T , inout c: S ){
  let temp = a
  a = b
  b = temp
  c = "Hi"
}
var aInt  = 5
var bInt  = 98
var cStr  = "Hello"
swapTwoValues(&aInt, &bInt,&cStr)

这会显示错误,但为什么?

我设置&#34; S&#34;到字符串类型,它似乎是正确的

2 个答案:

答案 0 :(得分:1)

这不起作用的原因是因为A: B语法要求通用占位符表示符合协议或从基类继承的任何类型。由于String是结构,而不是协议或类,因此会出现错误(&#34;继承自非协议,非类型类型'String'“)。如果你尝试了Optional这样的枚举,你会得到同样的结果。

这是为什么?泛型的目的是允许您为多种可能的类型编写代码,然后在编译时让Swift允许该函数应用于满足该要求的多种不同类型。

结构不允许继承(只有类)。因此,当您说func f<S: String>(c: S)时,您将定义一个通用占位符S,它只能代表一种String而不是其他类型。这没有意义 - 您也可以将String指定为非通用参数,即func f(s: String),因为它可能不存在其他类型。

另一方面,类允许继承,所以如果你有一个类MyClass,你可以编写func f:<S: MyClass>(c: S),因为在编译时,也许你可以传入MyInheritedClass,一个类继承自MyClass

结构可以符合协议。因此,例如,假设您想要编写一些只在一个值大于另一个值时交换值的东西:

func swapIfGreater<T: Comparable>(inout a: T, inout b: T) {
    // this is allowed because conformance to the the 
    // Comparable protocol guarantees > is available
    if a > b {
        // avoid temporaries with this one weird trick :)
        (a, b) = (b, a)
    }
}

// i and j are Ints (a kind of struct)
var i = 40, j = 30
swapIfGreater(&i, &j)

// s1 and s2 are Strings
var s1 = "zebra", s2 = "aardvark"
swapIfGreater(&s1, &s2)

// Bool doesn’t support the Comparable protocol
// (false is not “less than” or “greater than” true)
// so this won’t compile:
var b1 = true, b2 = false
swapIfGreater(&b1, &b2)

在编译时,当调用swapIfGreater时,Swift会查看通用占位符T的插槽中使用的类型(此处为IntString) ,并检查它们是否符合要求(它们需要符合协议Comparable)。如果是这样,您可以将其视为为您传入的每个有效类型专门编写函数版本:

// It’s as if Swift writes two versions of swapIfGreater for you automatically:
func swapIfGreater(inout a: Int, inout b: Int) {
    if a > b {
        (a, b) = (b, a)
    }
}

func swapIfGreater(inout a: String, inout b: String) {
    if a > b {
        (a, b) = (b, a)
    }
}

答案 1 :(得分:0)

代码<S: String>不应该起作用,原因很简单,String是一个结构体,并且不能扩展结构体。所以S实际上是一种无效的类型。

如果您希望将c作为枚举,则应使用<S: RawRepresentable where S.RawType == String>

如果您正在考虑向String类型添加功能,那么您应该将c作为普通String,然后在String上使用扩展来实现该功能。

如果您实际上想要将String扩展为对象,则应该扩展NSString。

例如:

class MyString: NSString {
  // My code
}

然后您的通用变为:<S: NSString>,这是完全有效的。

扩展NSString的缺点是类型现在是一个引用类型,但这只是Swift的一部分,你不能扩展(在继承方面)一个结构。