Swift中的generics – “通用参数”T“无法推断
我想从一个方法返回符合MyProtocol
的UIViewController
,所以我使用方法签名:
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T {
首先,我不明白:如果myMethod
返回例如一个MyViewController
必须签名,我必须强制转换它:
class MyViewController: UIViewController, MyProtocol
我不能简单地return MyViewController()
但我需要像这样return MyViewController() as! T
: return MyViewController() as! T
return MyViewController() as! T
– 为什么这是必要的?
第二件事:我怎样才能在某个地方使用这个方法? 我不能简单地说
let x = myMethod() as? UIViewController
因为我得到的错误
Generic parameter 'T' could not be inferred
我怎么能做到这样的事情? 如果我把它投到MyViewController
它的作品,但我想避免,当然。
编辑:例子
class MyViewController : UIViewController, MyProtocol { } protocol MyProtocol { } func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? }
好的,我确实得到了一个部分,但是为什么对T
要演员? MyViewController
是UIViewController
的子类,符合协议,所以不需要强制转换,对吗?
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T
这个声明说:存在一个名为myMethod
的函数, myMethod
返回一些特定的 T
,其中T
是UIViewController
的子types,也是MyProtocol
。 这并不是说T
实际上是什么types,并不是说只有一个这样的myMethod
。 如果有许多types都是UIViewController
子类并符合MyProtocol
,则可以有很多。 这些types中的每一个都创build了myMethod
的新版本( myMethod
是一个新的解决scheme,这个函数确实存在)。
这不是一回事:
func myMethod() -> UIViewController
这就是说:函数myMethod
返回UIViewController
任何子types。
Swift没有办法expression“任何types的UIViewController的子类,并且是MyProtocol的子types”。 你只能讨论符合标准的特定types。 Swift无法以这种方式组合类和协议; 这只是当前语言的限制,而不是一个深刻的devise问题。
具体对任何是问题。 有许多函数可以满足你的myMethod
声明。 每一个你可以插入符合规则将是一个候选人。 所以当你说myMethod()
,编译器不知道你的意思是哪个特定的。
(我打算扩大这个答案,用更less的types理论来提供这个答案,更多的是“如何用代码来做”,但是donnywals已经有了一个很好的版本。)
*到你编辑的问题*
func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? }
T
是由呼叫者决定的特定types。 不是“符合的任何types”是“符合某些具体,具体的types”。 考虑你所说的情况:
let vc: SomeOtherViewController = myMethod()
在这种情况下, T
是SomeOtherViewController
。 MyViewController
不是那种types,所以你在做什么as!
演员是危险的。
在这样的方法中,返回T
意味着你必须返回T
如果你返回MyViewController
,返回types应该是MyViewController
。 T
是一个genericstypes,它将采用Swift编译器可以推断的forms。
所以,在您的方法签名中,协议和方法的简单实现可能如下所示。
protocol MyProtocol { var name: String { get set } } func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { var vc = T() vc.name = "Hello, world" return vc }
所以,考虑你的使用例子:
let x = myMethod()
编译器如何知道T
的具体types是什么? 没有任何提示MyViewController
的提示。 我们唯一知道的是,无论T
是什么,它应该是MyViewController
或它的一个子类。 它应该符合MyProtocol
。 但是这并没有提供有关T
应该是什么types的信息。
编译器唯一能够推断出我们想要T
是通过返回值。 <>
之间的所有代码都是允许T
约束条件。 -> T
是在约束之外看到-> T
的唯一的地方。 所以如果我们能够告诉编译器我们希望myMethod
返回什么,我们已经给了它足够的信息来推断T
你的types转换工作,但我同意这不是很漂亮。 编译器推断T
更好方法是这样的。
let vc: MyViewController = myMethod()
通过指定vc
的types,编译器明白我们希望myMethod
返回一个MyViewController
。 所以现在T
的types可以推断,如果我们返回T
,我们实际上返回MyViewController
。