将类型传递给通用 Swift 扩展,或者理想地推断它
Pass in a type to a generic Swift extension, or ideally infer it
假设你有
class Fancy:UIView
您想查找所有同级 Fancy
视图。 ...
for v:UIView in superview!.subviews
{
if let f = v as? Fancy
{ f.hungry = false }
}
所以,尝试扩展,
public extension UIView
{
internal func fancySiblings()->([Fancy])
{
return (self.superview!
.subviews
.filter { [=13=] != self }
.flatMap { [=13=] as? Fancy }
)
}
}
太棒了,你现在可以了
for f:Fancy in self.fancySiblings()
{ f.hungry = false }
太棒了。
但是,
如何将该扩展概括为适用于任何 UIView 子类型?
理想情况下,扩展 甚至可以推断类型 ?以及打字?
所以,像...
public extension UIView
{
internal func siblings<T>( something T )->([T])
{
return (self.superview!
.subviews
.filter { [=15=] != self }
.flatMap { [=15=] as? T }
)
}
然后你可以这样称呼它...
for f in self.siblings(Fancy)
for p in self.siblings(Prancy)
for b in self.siblings(UIButton)
你怎么能像那样“告诉”通用扩展要使用的类型?
看来你可以“反推”了,
public extension UIView
{
internal func incredible<T>()->([T])
{
return (self.superview!
.subviews
.filter { [=17=] != self }
.flatMap { [=17=] as? T }
)
}
for f:Fancy in self.incredible()
for p:Prancy in self.incredible()
这很神奇,但反过来就不行了。
你甚至可以...
self.siblings().forEach{
(f:Fancy) in
d.hasRingOn = false
}
所以我仍然想知道如何“传入”类似 for f in self.siblings(Fancy)
的类型,理想情况下,甚至还可以推断它。
只需使用 .Type
:
internal func siblings<T>( something : T.Type)->([T]) {
...
}
之后 for f in self.siblings(Fancy)
应该完全按预期工作。
完整的工作示例:
class Fancy : UIView {}
public extension UIView {
internal func siblings<T>( _ : T.Type)->([T]) {
return (self.superview!
.subviews
.filter { [=11=] != self }
.flatMap { [=11=] as? T }
)
}
}
let superView = UIView()
let view = UIView()
superView.addSubview(view)
superView.addSubview(UIView())
superView.addSubview(Fancy())
print(view.siblings(Fancy))
正确输出一个 Fancy
视图!
解决请求的添加,以选择性地使用显式类型参数或使编译器的类型推断生效。您可以在同一扩展中创建第二个方法
internal func siblings<T>()->([T]) {
return siblings(T)
}
这种方式提供显式类型参数调用方法一,省略它需要您使其可推断并调用第二个函数,后者在内部调用第一个函数。
或,您可以使用更 快速 的方式,并使显式类型参数成为可选的,默认为 nil
.值得注意的是,这将在省略类型参数的情况下强制进行推断:
// power extension, it provides both infered or stated typing
internal func siblings<T>(_ : T.Type? = nil) -> ([T]) {
return (self.superview!
.subviews
.filter { [=13=] != self }
.flatMap { [=13=] as? T }
)
}
这将使您能够通过
调用该方法
for f in self.siblings(Fancy)
甚至
for f : Fancy in self.siblings()
两者都可以工作,但仍然只定义一个函数。
与之前所说的类似的答案,但更加精简,无需传递任何内容或多次迭代子视图:
extension UIView {
internal func siblings<T: UIView>() -> [T] {
return superview?.subviews.flatMap {return ([=10=] == self) ? nil : ([=10=] as? T) } ?? []
}
}
或者我对使用选项的偏好:
internal func siblings<T: UIView>() -> [T]? {
return superview?.subviews.flatMap {return ([=11=] == self) ? nil : [=11=] as? T }
}
用法示例:
class ExampleView: UIView {
func getMatchingSiblings(){
let foundSiblings: [ExampleView] = siblings()
}
//or with the for loop in the question:
for item: ExampleView in siblings() {
}
}
在处理泛型时,您只需要在方法的签名中包含一个泛型类型的实例。因此,如果您有参数或使用泛型的 return 类型,则无需传递类型。
假设你有
class Fancy:UIView
您想查找所有同级 Fancy
视图。
for v:UIView in superview!.subviews
{
if let f = v as? Fancy
{ f.hungry = false }
}
所以,尝试扩展,
public extension UIView
{
internal func fancySiblings()->([Fancy])
{
return (self.superview!
.subviews
.filter { [=13=] != self }
.flatMap { [=13=] as? Fancy }
)
}
}
太棒了,你现在可以了
for f:Fancy in self.fancySiblings()
{ f.hungry = false }
太棒了。
但是,
如何将该扩展概括为适用于任何 UIView 子类型?
理想情况下,扩展 甚至可以推断类型 ?以及打字?
所以,像...
public extension UIView
{
internal func siblings<T>( something T )->([T])
{
return (self.superview!
.subviews
.filter { [=15=] != self }
.flatMap { [=15=] as? T }
)
}
然后你可以这样称呼它...
for f in self.siblings(Fancy)
for p in self.siblings(Prancy)
for b in self.siblings(UIButton)
你怎么能像那样“告诉”通用扩展要使用的类型?
看来你可以“反推”了,
public extension UIView
{
internal func incredible<T>()->([T])
{
return (self.superview!
.subviews
.filter { [=17=] != self }
.flatMap { [=17=] as? T }
)
}
for f:Fancy in self.incredible()
for p:Prancy in self.incredible()
这很神奇,但反过来就不行了。
你甚至可以...
self.siblings().forEach{
(f:Fancy) in
d.hasRingOn = false
}
所以我仍然想知道如何“传入”类似 for f in self.siblings(Fancy)
的类型,理想情况下,甚至还可以推断它。
只需使用 .Type
:
internal func siblings<T>( something : T.Type)->([T]) {
...
}
之后 for f in self.siblings(Fancy)
应该完全按预期工作。
完整的工作示例:
class Fancy : UIView {}
public extension UIView {
internal func siblings<T>( _ : T.Type)->([T]) {
return (self.superview!
.subviews
.filter { [=11=] != self }
.flatMap { [=11=] as? T }
)
}
}
let superView = UIView()
let view = UIView()
superView.addSubview(view)
superView.addSubview(UIView())
superView.addSubview(Fancy())
print(view.siblings(Fancy))
正确输出一个 Fancy
视图!
解决请求的添加,以选择性地使用显式类型参数或使编译器的类型推断生效。您可以在同一扩展中创建第二个方法
internal func siblings<T>()->([T]) {
return siblings(T)
}
这种方式提供显式类型参数调用方法一,省略它需要您使其可推断并调用第二个函数,后者在内部调用第一个函数。
或,您可以使用更 快速 的方式,并使显式类型参数成为可选的,默认为 nil
.值得注意的是,这将在省略类型参数的情况下强制进行推断:
// power extension, it provides both infered or stated typing
internal func siblings<T>(_ : T.Type? = nil) -> ([T]) {
return (self.superview!
.subviews
.filter { [=13=] != self }
.flatMap { [=13=] as? T }
)
}
这将使您能够通过
调用该方法for f in self.siblings(Fancy)
甚至
for f : Fancy in self.siblings()
两者都可以工作,但仍然只定义一个函数。
与之前所说的类似的答案,但更加精简,无需传递任何内容或多次迭代子视图:
extension UIView {
internal func siblings<T: UIView>() -> [T] {
return superview?.subviews.flatMap {return ([=10=] == self) ? nil : ([=10=] as? T) } ?? []
}
}
或者我对使用选项的偏好:
internal func siblings<T: UIView>() -> [T]? {
return superview?.subviews.flatMap {return ([=11=] == self) ? nil : [=11=] as? T }
}
用法示例:
class ExampleView: UIView {
func getMatchingSiblings(){
let foundSiblings: [ExampleView] = siblings()
}
//or with the for loop in the question:
for item: ExampleView in siblings() {
}
}
在处理泛型时,您只需要在方法的签名中包含一个泛型类型的实例。因此,如果您有参数或使用泛型的 return 类型,则无需传递类型。