Generics 从函数和方法返回受约束的泛型
我想创建一个函数,返回符合协议的对象,但协议使用Generics 从函数和方法返回受约束的泛型,generics,swift,protocols,type-alias,Generics,Swift,Protocols,Type Alias,我想创建一个函数,返回符合协议的对象,但协议使用typealias。给出以下玩具示例: protocol HasAwesomeness { typealias ReturnType func hasAwesomeness() -> ReturnType } extension String: HasAwesomeness { func hasAwesomeness() -> String { return "Sure Does!" }
typealias
。给出以下玩具示例:
protocol HasAwesomeness {
typealias ReturnType
func hasAwesomeness() -> ReturnType
}
extension String: HasAwesomeness {
func hasAwesomeness() -> String {
return "Sure Does!"
}
}
extension Int: HasAwesomeness {
func hasAwesomeness() -> Bool {
return false
}
}
String
和Int
已被扩展以符合hasaweomeness
,并且每个实现了hasaweomeness()
方法以返回不同的类型
现在我想创建一个类,它返回一个符合hasaweomeness
协议的对象。我不在乎类是什么,只是我可以发送消息hasAwesomenss()
。当我尝试以下操作时,会生成一个编译错误:
class AmazingClass: NSObject {
func returnsSomethingWithAwesomeness(key: String) -> HasAwesomeness {
...
}
}
错误:协议“hasaweomeness”只能用作一般约束,因为它具有自身或关联的类型要求
可以想象,returnssomethingwithawomeness
的目的是基于键
参数返回一个字符串
或Int
。编译器抛出的错误在某种程度上解释了为什么不允许它,但它确实提供了修复语法的见解
func returnsSomethingWithAwesomeness<T: HasAwesomeness>(key: String) -> T
{
...
}
错误:类型“T”不符合协议“StringLiteralConverable”
错误:类型“T”不符合协议“IntegerLiteralConverable”
好吧,现在我被卡住了。有人能帮我填补一下我对类型和泛型的理解上的空白吗?可能会让我找到有用的资源吗?我认为理解这里发生的事情的关键是区分在运行时动态确定的事情和在编译时静态确定的事情。在大多数语言(如Java)中,协议(或接口)都是关于在运行时获取多态行为的,而在Swift中,具有关联类型的协议也用于在编译时获取多态行为,这一点没有帮助 每当您看到一个通用占位符时,比如示例中的
T
,这个T
的类型将在编译时确定。因此,在您的示例中:
func returnCollectionContainingOne<C: ExtensibleCollectionType where C.Generator.Element == Int>() -> C {
// this is allowed because the ExtensibleCollectionType procol
// requires the type implement an init() that takes no parameters
var result = C()
// and it also defines an `append` function that allows you to do this:
result.append(1)
// note, the reason it was possible to give a "1" as the argument to
// append was because of the "where C.Generator.Element == Int" part
// of the generic placeholder constraint
return result
}
// now you can use returnCollectionContainingOne with arrays:
let a: [Int] = returnCollectionContainingOne()
// or with ContiguousArrays:
let b: ContiguousArray = returnCollectionContainingOne()
func返回具有某种意义的方法(键:字符串)->T
是这样说的:returnsMethingWisaweomeness
是一个可以对任何类型的T
进行操作的函数,只要T
符合Hasaweomeness
但是T
的填写内容是在returns点确定的。调用具有某种意义的mething
时–Swift将查看呼叫站点上的所有信息,确定T
是什么类型,并用该类型替换所有T
占位符*
因此,假设在调用站点,选择T
是一个String
,您可以将returnsMethingWithsomeness
视为所有出现的占位符T
都被替换为String
:
// giving the type of s here fixes T as a String
let s: String = returnsSomethingWithAwesomeness("bar")
func returnsSomethingWithAwesomeness(key: String) -> String {
if key == "foo" {
return "Amazing Foo"
}
else {
return 42
}
}
注意,T
替换为String
,而不是hasaweomeness
类型hasaweomeness
仅用作约束–即限制可能的类型T
当你这样看它时,你会发现else
中的return42
毫无意义——你怎么能从一个返回字符串的函数中返回42呢
为了确保returnsMethingWithsomeness
可以处理T
最终出现的任何功能,Swift限制您仅使用那些保证在给定约束下可用的功能。在这种情况下,我们所知道的关于T
的一切就是它符合hasaweomeness
。这意味着您可以在任何T
上调用returnsMethingWithawesomeness
方法,或者将它与另一个函数一起使用,该函数将一个类型约束为hasaweomeness
,或者将一个T
类型的变量分配给另一个变量(所有类型都支持赋值),也就是它
您无法将其与其他Ts进行比较(不能保证它支持==
)。您不能构造新的方法(谁知道t
是否有合适的初始化方法?)。您不能从字符串或整数文本创建它(这样做需要t
符合stringliteralcoverable
或integerliteralcoverable
,这并不一定——因此,当您尝试使用这些类型的文本之一创建类型时,会出现这两个错误)
可以编写泛型函数,返回所有符合协议的泛型类型。但是返回的是特定类型,而不是协议,因此不会动态确定哪种类型。例如:
func returnCollectionContainingOne<C: ExtensibleCollectionType where C.Generator.Element == Int>() -> C {
// this is allowed because the ExtensibleCollectionType procol
// requires the type implement an init() that takes no parameters
var result = C()
// and it also defines an `append` function that allows you to do this:
result.append(1)
// note, the reason it was possible to give a "1" as the argument to
// append was because of the "where C.Generator.Element == Int" part
// of the generic placeholder constraint
return result
}
// now you can use returnCollectionContainingOne with arrays:
let a: [Int] = returnCollectionContainingOne()
// or with ContiguousArrays:
let b: ContiguousArray = returnCollectionContainingOne()
func returnCollectionContainingOne()->C{
//这是允许的,因为ExtensionType procol
//要求类型实现不带参数的init()
var result=C()
//它还定义了一个“append”函数,允许您执行以下操作:
结果。追加(1)
//请注意,可以将“1”作为参数的原因
//追加是因为“where C.Generator.Element==Int”部分
//通用占位符约束的定义
返回结果
}
//现在,您可以将returnCollectionContainingOne与数组一起使用:
设a:[Int]=returnCollectionContainingOne()
//或使用连续阵列:
设b:ContiguousArray=returnCollectionContainingOne()
将此代码中的returnCollectionContainingOne
视为两个函数,一个用于ContiguousArray
,另一个用于Array
,由编译器在调用它们时自动编写(因此可以将C
固定为特定类型)。不是一个返回协议的函数,而是两个返回两种不同类型的函数。因此,以同样的方式returnsMething