这是我的代码:
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;到字符串类型,它似乎是正确的
答案 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
的插槽中使用的类型(此处为Int
或String
) ,并检查它们是否符合要求(它们需要符合协议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的一部分,你不能扩展(在继承方面)一个结构。