Swift 中的扩展函数、扩展静态函数和扩展 class 函数之间有什么区别?
What's the difference between an Extension func, Extension static func & Extension class func in Swift?
我试图在 UIColor 上创建一个扩展函数,它可以将 Card.Colour 类型的参数和 return UIColor 返回给调用者。
button.backgroundColor = UIColor.getColour(cardColour: cardToDeal.colour)
extension UIColor {
func getColour(cardColour: Card.Colour) -> UIColor {
switch cardColour {
case .Red:
return UIColor.red
case .Green:
return UIColor.green
case .Blue:
return UIColor.blue
}
}
}
当我尝试这样做时,UIColor.getColour的扩展函数要求我在扩展方法中输入 UIColor 类型的参数,而不是 Card.Colour 的指定类型。
但是,当我将 getColour 的扩展函数更改为:
static func getColour(cardColour: Card.Colour) -> UIColor {
class func getColour(cardColour: Card.Colour) -> UIColor {
它允许我传递 Card.Colour
类型的参数
这是为什么?为什么将函数更改为静态函数或 class 函数会更改需要传入的类型?
提前致谢!
(如能详细解答,将不胜感激)
扩展方法对提供类型的实例进行操作。您可以在方法块内使用实例的所有 internal
属性和方法。
static
方法是由 class 名称命名空间的方法,不对您的 class 的任何特定实例进行操作。 class
方法几乎相同,只是 class
和 static
之间的区别在于,您可以在 subclass 中使用 override
class
方法].
记住 UIColor
是 class。 class 有点像您用来创建符合 class 的实例或对象的蓝图。 UIColor.red
是 UIColor
class.
的一个实例
当您在 class 中定义 func
时(在您的情况下,作为扩展),Swift 假定您要将 func
添加到蓝图,它将依次在 UIColor
class 的所有实例中可用,例如 UIColor.red
.
您还可以在所有 class 之外定义您的 func
,只需将它放在模块的顶层,而不是在 extension
.[=52 中=]
但是,为了使您的函数井井有条,您可以将类似的函数放在 class 名称中。您只需告诉 Swift 您不是要将函数添加到将应用于所有 实例 的蓝图中,而是您想要的只是拥有一个函数,其名称以 class.
的名称为前缀
这里有一个例子来说明用法上的区别:
class Test {
func notStatic() {
print("called from an instance")
}
static func thisIsStatic() {
print("called on class name directly")
}
}
let instance = Test() // this is an *instance* of Test
instance.notStatic() // we can call a non static func on instance
Test.thisIsStatic() // we can call a static func directly on the class only
现在,让我们暂时回到您的具体示例。请注意,在您的示例中,您从 Card.Colour
的实例开始并尝试创建 UIColor
.
的 new 实例
换句话说,将 func
添加到 UIColor
实例 (即非 static
或 class
) 对你没用,因为你还没有 UIColor
的实例。
创建 class 新实例的惯用方法是使用初始化器 (init
)。所以你可以像这样把你的函数变成 UIColor 的初始化器:
extension UIColor {
convenience init(cardColour: Card.Colour) {
switch cardColour {
case .Red: self.init(cgColor: UIColor.red.cgColor)
case .Blue: self.init(cgColor: UIColor.blue.cgColor)
case .Green: self.init(cgColor: UIColor.green.cgColor)
}
}
}
现在您只需调用 UIColor(cardColour: .Red)
即可获得您想要的。请注意,在实现中,我将 UIColor.red
转换为 cgColor
并作为快速破解。对于 Card.Colour
.
的每种情况,请随意使用您认为适合 UIColor
的初始化程序
但还有另一种方式,我认为这种方式更加优雅。由于您已经有一个 Card.Colour
的 实例 ,您可以使用一个函数扩展 Card.Colour
,为您提供对应于该实例的 UIColor
。在该函数中,您可以使用关键字 self
.
引用 Card.Colour
实例
由于您已经拥有 Card.Colour
到 self
的实例,因此您不需要向该函数传递任何参数。这允许您使用称为 计算属性 的很酷的功能,使使用更加方便。
这就是您将这样的扩展添加到 Card.Colour
的方式:
extension Card.Colour {
var uiColor: UIColor {
switch self {
case .Red: return .red
case .Blue: return .blue
case .Green: return .green
}
}
}
然后你可以从 Card.Colour
得到一个 UIColor
像这样 Card.Colour.Red.uiColor
或 mainColour.uiColor
,其中 mainColour
是类型 Card.Colour
.
最后,正如 Leo Dabus 在评论中指出的那样,Swift's naming conventions 是大小写应以小写字母开头。您应该使用 Card.Colour.red
而不是 Card.Colour.Red
,等等。这些约定出现了大约 Swift 3 次。在此之前将案例名称大写是很常见的。
我试图在 UIColor 上创建一个扩展函数,它可以将 Card.Colour 类型的参数和 return UIColor 返回给调用者。
button.backgroundColor = UIColor.getColour(cardColour: cardToDeal.colour)
extension UIColor {
func getColour(cardColour: Card.Colour) -> UIColor {
switch cardColour {
case .Red:
return UIColor.red
case .Green:
return UIColor.green
case .Blue:
return UIColor.blue
}
}
}
当我尝试这样做时,UIColor.getColour的扩展函数要求我在扩展方法中输入 UIColor 类型的参数,而不是 Card.Colour 的指定类型。
但是,当我将 getColour 的扩展函数更改为:
static func getColour(cardColour: Card.Colour) -> UIColor {
class func getColour(cardColour: Card.Colour) -> UIColor {
它允许我传递 Card.Colour
类型的参数这是为什么?为什么将函数更改为静态函数或 class 函数会更改需要传入的类型?
提前致谢!
(如能详细解答,将不胜感激)
扩展方法对提供类型的实例进行操作。您可以在方法块内使用实例的所有 internal
属性和方法。
static
方法是由 class 名称命名空间的方法,不对您的 class 的任何特定实例进行操作。 class
方法几乎相同,只是 class
和 static
之间的区别在于,您可以在 subclass 中使用 override
class
方法].
记住 UIColor
是 class。 class 有点像您用来创建符合 class 的实例或对象的蓝图。 UIColor.red
是 UIColor
class.
当您在 class 中定义 func
时(在您的情况下,作为扩展),Swift 假定您要将 func
添加到蓝图,它将依次在 UIColor
class 的所有实例中可用,例如 UIColor.red
.
您还可以在所有 class 之外定义您的 func
,只需将它放在模块的顶层,而不是在 extension
.[=52 中=]
但是,为了使您的函数井井有条,您可以将类似的函数放在 class 名称中。您只需告诉 Swift 您不是要将函数添加到将应用于所有 实例 的蓝图中,而是您想要的只是拥有一个函数,其名称以 class.
的名称为前缀这里有一个例子来说明用法上的区别:
class Test {
func notStatic() {
print("called from an instance")
}
static func thisIsStatic() {
print("called on class name directly")
}
}
let instance = Test() // this is an *instance* of Test
instance.notStatic() // we can call a non static func on instance
Test.thisIsStatic() // we can call a static func directly on the class only
现在,让我们暂时回到您的具体示例。请注意,在您的示例中,您从 Card.Colour
的实例开始并尝试创建 UIColor
.
换句话说,将 func
添加到 UIColor
实例 (即非 static
或 class
) 对你没用,因为你还没有 UIColor
的实例。
创建 class 新实例的惯用方法是使用初始化器 (init
)。所以你可以像这样把你的函数变成 UIColor 的初始化器:
extension UIColor {
convenience init(cardColour: Card.Colour) {
switch cardColour {
case .Red: self.init(cgColor: UIColor.red.cgColor)
case .Blue: self.init(cgColor: UIColor.blue.cgColor)
case .Green: self.init(cgColor: UIColor.green.cgColor)
}
}
}
现在您只需调用 UIColor(cardColour: .Red)
即可获得您想要的。请注意,在实现中,我将 UIColor.red
转换为 cgColor
并作为快速破解。对于 Card.Colour
.
UIColor
的初始化程序
但还有另一种方式,我认为这种方式更加优雅。由于您已经有一个 Card.Colour
的 实例 ,您可以使用一个函数扩展 Card.Colour
,为您提供对应于该实例的 UIColor
。在该函数中,您可以使用关键字 self
.
Card.Colour
实例
由于您已经拥有 Card.Colour
到 self
的实例,因此您不需要向该函数传递任何参数。这允许您使用称为 计算属性 的很酷的功能,使使用更加方便。
这就是您将这样的扩展添加到 Card.Colour
的方式:
extension Card.Colour {
var uiColor: UIColor {
switch self {
case .Red: return .red
case .Blue: return .blue
case .Green: return .green
}
}
}
然后你可以从 Card.Colour
得到一个 UIColor
像这样 Card.Colour.Red.uiColor
或 mainColour.uiColor
,其中 mainColour
是类型 Card.Colour
.
最后,正如 Leo Dabus 在评论中指出的那样,Swift's naming conventions 是大小写应以小写字母开头。您应该使用 Card.Colour.red
而不是 Card.Colour.Red
,等等。这些约定出现了大约 Swift 3 次。在此之前将案例名称大写是很常见的。