ios Swift 中的泛型 - “无法推断出泛型参数‘T’
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38999102/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generics in Swift - "Generic parameter 'T' could not be inferred
提问by swalkner
I'd like to return a UIViewController
conforming to MyProtocol
from a method, so I'm using the method signature:
我想从一个方法返回一个UIViewController
符合MyProtocol
,所以我使用了方法签名:
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T {
First thing I don't understand: if myMethod
returns e.g. a MyViewController
which has to following signature, I have to force cast it:
我不明白的第一件事:如果myMethod
返回例如 aMyViewController
必须遵循签名,我必须强制转换它:
class MyViewController: UIViewController, MyProtocol
I cannot simply return MyViewController()
but I need to cast it like this: return MyViewController() as! T
- why is this necessary?
我不能简单地return MyViewController()
但我需要像这样投射它:return MyViewController() as! T
- 为什么这是必要的?
And the second thing: how can I use this method somewhere? I cannot simply say
第二件事:我如何在某处使用这种方法?我不能简单地说
let x = myMethod() as? UIViewController
as I get the error
当我收到错误时
Generic parameter 'T' could not be inferred
How can I achieve something like this? If I cast it to MyViewController
it works, but I would like to avoid that of course.
我怎样才能实现这样的目标?如果我将其转换MyViewController
为有效,但我当然想避免这种情况。
EDIT: Example
编辑:示例
class MyViewController : UIViewController, MyProtocol {
}
protocol MyProtocol {
}
func myMethod<T>() -> T where T : UIViewController, T : MyProtocol {
return MyViewController() as! T // why is the cast necessary?
}
ok, I do get one part, but why is the cast to T
necessary? MyViewController
is a subclass of UIViewController
and conforms to the protocol, so no cast should be necessary, right?
好的,我确实得到了一部分,但为什么T
需要演员阵容?MyViewController
是UIViewController
符合协议的子类,所以不需要强制转换,对吧?
回答by Rob Napier
func myMethod<T where T : UIViewController, T : MyProtocol>() -> T
This declaration says: There exists a function called myMethod
, such that myMethod
returns some specificT
where T
is a subtype of UIViewController
and also MyProtocol
. This does not say what type T
actually is, and it does not say that there is only one such myMethod
. There can be many if there are many type that are both subclasses of UIViewController
and conform to MyProtocol
. Every one of those types creates a new version of myMethod
(really a new solution to the assertion myMethod
makes, that such a function does exist).
这个声明说:存在一个名为 的函数myMethod
,它myMethod
返回一些特定的T
whereT
是UIViewController
and的子类型MyProtocol
。这并没有说明T
实际上是什么类型,也没有说只有一种这样的myMethod
。如果有许多类型既是 的子类UIViewController
又符合MyProtocol
. 这些类型中的每一种都创建了一个新版本myMethod
(确实是断言的新解决方案myMethod
,这样的函数确实存在)。
This is not the same thing as:
这与以下内容不同:
func myMethod() -> UIViewController
That says: The function myMethod
returns any subtype of UIViewController
.
也就是说:该函数myMethod
返回UIViewController
.
There is no way in Swift to express "any type that is a subclass of UIViewController and is a subtype of MyProtocol." You can only discuss a specific type that meets that criterial. Swift can't combine classes and protocols this way; it's just a current limitation of the language, not a deep design issue.
在 Swift 中无法表达“任何类型是 UIViewController 的子类并且是 MyProtocol 的子类型”。您只能讨论符合该标准的特定类型。Swift 不能以这种方式组合类和协议;这只是语言的当前限制,而不是深层设计问题。
The specificversus anyis the issue. There are many functions that satisfy your myMethod
declaration. Every T
you can plug in that conforms to the rules would be a candidate. So when you say myMethod()
, the compiler doesn't know which specific T
you mean.
在具体的与任何的问题。有许多函数可以满足您的myMethod
声明。每一个T
你能插入的符合规则的都将成为候选人。所以当你说 时myMethod()
,编译器不知道T
你的意思是哪个特定的。
(I was going to expand this answer to provide it in less type-theory, more "how do you do it in code" terms, but donnywals already has an excellent version of that.)
(我打算扩展这个答案,以更少的类型理论,更多的“你如何用代码来做”的术语来提供它,但是 donnywals 已经有了一个很好的版本。)
* To your edited question *
* 对于您编辑的问题 *
func myMethod<T>() -> T where T : UIViewController, T : MyProtocol {
return MyViewController() as! T // why is the cast necessary?
}
T
is a specifictype decided by the caller. It is not "any type that conforms" it is "some specific, concrete type that conforms." Consider the case that you called:
T
是由调用者决定的特定类型。它不是“任何符合的类型”,而是“符合的某种特定的、具体的类型”。考虑您调用的案例:
let vc: SomeOtherViewController = myMethod()
In this case, T
is SomeOtherViewController
. MyViewController
is not that type, so what you're doing with the as!
cast is dangerous.
在这种情况下,T
是SomeOtherViewController
。MyViewController
不是那种类型,所以你对as!
演员所做的事情很危险。
回答by donnywals
In a method like this, returning T
means you have to return T
. If you return MyViewController
, the return type should be MyViewController
. T
is a generic type that will take the form of whatever the Swift compiler can infer it to be.
在这样的方法中,返回T
意味着您必须返回T
. 如果返回MyViewController
,返回类型应该是MyViewController
. T
是一个泛型类型,它将采用 Swift 编译器可以推断出的任何形式。
So, with your method signature, a simple implementation of the protocol and method could look like this.
因此,使用您的方法签名,协议和方法的简单实现可能如下所示。
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
}
So, considering your usage example:
因此,考虑您的使用示例:
let x = myMethod()
How would the compiler know what the concrete type of T
is? There is nothing giving it a hint of MyViewController
. The only thing we know is that whatever T
is, it should be MyViewController
or a subclass of it. And it should conform to MyProtocol
. But this does not provide information about what the type of T
should be.
编译器如何知道具体类型T
是什么?没有任何暗示MyViewController
。我们唯一知道的是,无论T
是什么,它都应该是MyViewController
或它的子类。它应该符合MyProtocol
. 但这并没有提供关于T
应该是什么类型的信息。
The only place where the compiler can infer what we want T
to be is through the return value. All the code between <>
are constraints for what T
is allowed to be. -> T
is the only place where T
is seen outside of the constraints. So if we can somehow tell the compiler what we want myMethod
to return, we have given it enough information to infer T
.
编译器可以推断出我们想要什么的唯一地方T
是通过返回值。之间的所有代码<>
都是T
允许的约束。-> T
是唯一可以在T
约束之外看到的地方。所以如果我们能以某种方式告诉编译器我们想要myMethod
返回什么,我们就已经给了它足够的信息来推断T
.
Your typecast works but I agree that it's not very pretty. A much prettier way for the compiler to infer T
is this.
您的类型转换有效,但我同意它不是很漂亮。编译器推断的一种更漂亮的方法T
是这样。
let vc: MyViewController = myMethod()
By specifying the type of vc
, the compiler understands that we want myMethod
to return a MyViewController
. So now T
's type can be inferred and if we return T
, we actually return MyViewController
.
通过指定 的类型vc
,编译器知道我们想要myMethod
返回一个MyViewController
。所以现在T
的类型可以被推断出来,如果我们返回T
,我们实际上返回MyViewController
。
回答by Lukas
As some pointed out in the comments, there is no apparent reason for myMethod
to be generic. The argument for doing so is: (quoting from your comment)
正如一些人在评论中指出的那样,没有明显的理由myMethod
要通用。这样做的论点是:(引自您的评论)
I would like to work with a type that's a UIViewController and conforms to the specific protocol;
我想使用 UIViewController 类型并符合特定协议;
Lets call that type ViewControllerAndMyprotocol
,
让我们称之为类型ViewControllerAndMyprotocol
,
I do have different classes which conform to this rules, therefore I do not want to use a specific type
我确实有符合此规则的不同类,因此我不想使用特定类型
However myMethod
signature already constrains the type ViewControllerAndMyprotocol
i.e. caller is bound to receive a UIViewController
and not any of the "different classes which conform to this rules".
然而,myMethod
签名已经限制了类型,ViewControllerAndMyprotocol
即调用者必须接收 aUIViewController
而不是任何“符合此规则的不同类”。
The flexibility on what concrete types could be ViewControllerAndMyprotocol
, including MyViewController
is why there is type ambiguity in the statement let x = myMethod()
requiring casting: let x = myMethod() as? UIViewController
具体类型的灵活性ViewControllerAndMyprotocol
,包括MyViewController
为什么在let x = myMethod()
需要强制转换的语句中存在类型歧义:let x = myMethod() as? UIViewController
You can avoid the casting by changing myMethod
signature as such:
您可以通过更改myMethod
签名来避免强制转换:
typealias ViewControllerAndMyprotocol = UIViewController & MyProtocol
func myMethod() -> ViewControllerAndMyprotocol {
return MyViewController()
}
The statement let x = myMethod()
will not require casting and will be of type ViewControllerAndMyprotocol
which is also a UIViewController
.
该语句let x = myMethod()
不需要强制转换,并且其类型ViewControllerAndMyprotocol
也是UIViewController
.