Swift中的generics – “通用参数”T“无法推断

我想从一个方法返回符合MyProtocolUIViewController ,所以我使用方法签名:

 func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { 

首先,我不明白:如果myMethod返回例如一个MyViewController必须签名,我必须强制转换它:

 class MyViewController: UIViewController, MyProtocol 

我不能简单地return MyViewController()但我需要像这样return MyViewController() as! Treturn 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要演员? MyViewControllerUIViewController的子类,符合协议,所以不需要强制转换,对吗?

 func myMethod<T where T : UIViewController, T : MyProtocol>() -> T 

这个声明说:存在一个名为myMethod的函数, myMethod返回一些特定的 T ,其中TUIViewController的子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() 

在这种情况下, TSomeOtherViewControllerMyViewController不是那种types,所以你在做什么as! 演员是危险的。

在这样的方法中,返回T意味着你必须返回T 如果你返回MyViewController ,返回types应该是MyViewControllerT是一个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