Swift 是否可以将泛型参数约束为*非*可选?

Swift 是否可以将泛型参数约束为*非*可选?,swift,generics,Swift,Generics,假设我有以下代码: func hello<T>(thing: T) -> String { return "hello \(thing)" } 我在想,也许在T上使用协议一致性或where子句是可行的,但我想不出这到底是怎么回事 我之所以要这样做,是因为我在处理遗留代码库中的一个实际函数,如果thing为nil,则该函数没有合理的行为。因此,我宁愿阻止调用可选的hello,而不是在hello内部展开thing,并试图找出一个合理的错误行为 更新: 一个可能的路径…我意

假设我有以下代码:

func hello<T>(thing: T) -> String {
    return "hello \(thing)"
}
我在想,也许在T上使用协议一致性或
where
子句是可行的,但我想不出这到底是怎么回事

我之所以要这样做,是因为我在处理遗留代码库中的一个实际函数,如果
thing
为nil,则该函数没有合理的行为。因此,我宁愿阻止调用可选的
hello
,而不是在hello内部展开
thing
,并试图找出一个合理的错误行为

更新:

一个可能的路径…我意识到可选枚举符合
NilLiteralConvertible
协议。因此,如果我能找到一种方法将我的泛型限制为不符合某个类型,我就可以排除事实上的可选项。但我不知道是否有可能像这样做

<T where !T: NilLiteralConvertible>

我能想到的最好方法是重载并在运行时检查:

func hello<T>(thing: T) -> String {
    return "hello \(thing)"
}

fun hello<T>(thing: T?) -> String {
    fatalError("No optionals allowed!")
}

hello("swift")  // fine
hello(2)        // fine
hello(Int("2")) // fatal error
func hello(thing:T)->String{
返回“你好\(事情)”
}
有趣的你好(事物:T?->字符串{
fatalError(“不允许选择!”)
}
你好(“斯威夫特”)//很好
你好(2)//很好
hello(Int(“2”)//致命错误

但是我不知道如何生成编译时错误

您可以创建一个虚拟协议(
NOTFOPTIONALTYPE
),并通过该协议扩展您希望在泛型函数中使用的所有类型。最后,使用虚拟协议作为泛型函数中参数的类型约束;optionals不满足此类型约束,如果它们作为这些函数的参数发送,则在编译时会出现错误

// dummy protocol
protocol NotOfOptionalType {}

extension String : NotOfOptionalType {}
extension Int : NotOfOptionalType {}
extension Double : NotOfOptionalType {}
// ... extend to the types you will use

func hello<T: NotOfOptionalType > (thing: T) -> String {
    return "hello \(thing)"
}

let foo = "some"
var bar: String? = nil

print(hello(foo))  // compiles
print(hello(bar))  // fails at compile time
bar = "something"
print(hello(bar))  // fails at compile time
print(hello(bar!)) // compiles
//虚拟协议
协议NOTFOPTIONALTYPE{}
扩展字符串:NOTFOPTIONALTYPE{}
扩展名Int:NOTFOPTIONALTYPE{}
双扩展名:NOTFOPTIONALTYPE{}
// ... 扩展到您将使用的类型
func hello(thing:T)->String{
返回“你好\(事情)”
}
让foo=“一些”
变量栏:字符串?=无
打印(hello(foo))//编译
打印(hello(bar))//编译时失败
bar=“某物”
打印(hello(bar))//编译时失败
打印(hello(bar!))//编译

我不太清楚这个要求。什么样的函数可以“毫无限制地接受任何东西,除了一个名为Optional的特定枚举?”Optional有一点语言魔力,但在大多数情况下,它只是一个枚举类型。我的怀疑是,您真正想要做的是创建一个可以附加到您接受的类型的协议,而不是“除可选之外的任何内容”。“字面上的任何内容,没有任何限制,除了一个名为可选的特定枚举”几乎正是我想要的(或者更准确地说,除了“nil”之外的任何内容)。我猜当你用这种方式表达它时,如果没有某种依赖类型是不可能的,但是想要将一个类型约束为只包含特定的值,这对我来说是一个非常常见的用例。不清楚你的函数如何在“除nil以外的任何值”上工作。它做什么?奈尔在斯威夫特中并不是很神奇。它是合法值(
可选。无
)。它不是0或NULL之类的。您可以像处理任何其他枚举值一样处理nil。它本身并不像其他语言那样危险。在引发这个问题的特定情况下,一些遗留代码有一个函数,可以将t插入字符串,然后将字符串上载到服务器。在字符串中放入nil值(或“Optional.Some(“Thing”))是没有商业逻辑意义的,因此如果程序员正在这样做(就像遗留代码那样)这肯定是一个错误。我可能会做一些事情,比如重新编写函数来检查nil和optional以及noop(如果必要的话),但我宁愿通过使用编译器强制执行业务逻辑来防止程序员出错(如果可能的话)@Rogueleader你有时间看看我下面提出的解决方案是否适合你吗?我喜欢这个想法,但我刚刚尝试过,hello(bar)可以编译,但是cast在运行时而不是编译时失败。因此它不会阻止我所希望的程序员
self.shootFoot()
。我们可以添加
@可用(swift,弃用:2)
在函数顶部,使编译器发出警告
// dummy protocol
protocol NotOfOptionalType {}

extension String : NotOfOptionalType {}
extension Int : NotOfOptionalType {}
extension Double : NotOfOptionalType {}
// ... extend to the types you will use

func hello<T: NotOfOptionalType > (thing: T) -> String {
    return "hello \(thing)"
}

let foo = "some"
var bar: String? = nil

print(hello(foo))  // compiles
print(hello(bar))  // fails at compile time
bar = "something"
print(hello(bar))  // fails at compile time
print(hello(bar!)) // compiles