有没有办法一起使用模板、输入输出参数和可选参数?
Is there a way to use a Template, and In-Out Parameter and Optional together?
前几天我 运行 做了一些有趣的事。基本上我最初写了一个辅助函数来防止在自动类型转换 JSON 属性 时出错。它看起来像这样:
func readData<T>(inout output:T, _ input:AnyObject?, _ throwError:Bool = true) throws
{
if (input == nil) {
if (throwError) {
throw ConvertError.MissingParameter
}
}
else {
if let inputObject:T = input as? T {
output = inputObject
}
else if (throwError) {
throw ConvertError.WrongType
}
}
}
var myProperty:String
try readData(&myProperty, myJson["data"], true)
这会检查 属性 是否存在,并且它是正确的类型。如果一切顺利,myProperty 中的值会发生变化。
过了一会儿,我需要做一些改变。我制作了一个名为 properties 的 class,其中包含一个属性列表。这种类型的 class 有 2 个变量:originalProperties 和 modifiedProperties 这些 class 中的每个属性都是现在可选变量,专门用于跟踪用户更改了哪些属性。基本上它看起来像这样:
class Properties
{
var x:Int?
var y:Int?
}
现在当我运行这个:
try readData(&originalProperties.x, myJson["x"], false)
它不再起作用了。我查看了 another question,它解释了发生了什么。基本上 x 的值仍然是 nil (因为它是可选的),我将 nil 值传递到我的 readData 函数,所以模板类型设置不正确,这就是为什么它在 输入上失败的原因? T码.
幸运的是,我不用再拥有这样的创意功能了。我只能用这个:
originalProperties.x= obj["x"] as? Int
但是如果我需要的话,我会失去抛出错误的功能。
有没有人知道如何确保我的模板类型在其值为 nil 的情况下正确传递?我什至在另一个线程中读到我可能必须使用某种默认值闭包,但看看是否有办法解决这个问题会很有趣。
这里的主要问题是泛型 T
永远 自己 不知道它是否是 Optional
类型,这使得类型转换成功到 T
对于 T
实际上是 Optional<SomeType>
类型的情况来说很棘手。我们自己可以断言 T
是可选类型(检查 Mirror(reflecting: ...).displayStyle == .Optional
等),但这仍然不能立即解决到 T
的转换问题。相反,我们可以使用另一种方法,如下所示。
我们可以通过创建两个 readData(...)
函数来解决这个问题,一个采用可选的泛型 inout
参数,类型 U?
,另一个采用隐式 [=66] =] 泛型 inout
参数 U
(仅当 U?
函数无法使用时调用,因此隐式仅调用 non-optionals)。反过来,这两个函数是最小的,基本上只调用您的 "core" dataReader(..)
函数,我们在其中进行了调整,使 inout
泛型参数现在显式可选,即 T?
.
enum ConvertError: ErrorType {
case MissingParameter
case WrongType
}
/* optional inout parameter */
func readData<U>(inout output: U?, _ input: AnyObject?, _ throwError: Bool = true) throws {
try readDataCore(&output, input, throwError)
}
/* non-optional inout parameter */
func readData<U>(inout output: U, _ input: AnyObject?, _ throwError: Bool = true) throws {
var outputOpt : U? = output
try readDataCore(&outputOpt, input, throwError)
output = outputOpt!
/* you could use a guard-throw here for the unwrapping of 'outputOpt', but
note that 'outputOpt' is initialized with a non-nil value, and that it can
never become 'nil' in readDataHelper; so "safe" forced unwrapping here. */
}
/* "core" function */
func readDataCore<T>(inout output: T?, _ input: AnyObject?, _ throwError: Bool = true) throws
{
if (input == nil) {
if (throwError) {
throw ConvertError.MissingParameter
}
}
else {
if let inputObject: T = input as? T {
output = inputObject
}
else if (throwError) {
throw ConvertError.WrongType
}
}
}
当我们尝试这个时,我们发现我们现在得到了我们正在寻找的行为,即使作为 inout
参数发送的参数是 nil
或 Optional
。
示例 1:使用值为 nil
的可选 inout
参数
class Properties
{
var x:Int?
var y:Int?
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
do {
try readData(&originalProperties.x, myJson["data"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'originalProperties.x = 10', ok! */
// try some non-existing key 'foo'
do {
try readData(&originalProperties.x, myJson["foo"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'Missing parameter', ok! */
示例 2:使用可选的 inout
参数,但带有 non-optional 值
class Properties
{
var x:Int? = 1
var y:Int? = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */
示例 3:使用 non-optional inout
参数
class Properties
{
var x:Int = 1
var y:Int = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */
前几天我 运行 做了一些有趣的事。基本上我最初写了一个辅助函数来防止在自动类型转换 JSON 属性 时出错。它看起来像这样:
func readData<T>(inout output:T, _ input:AnyObject?, _ throwError:Bool = true) throws
{
if (input == nil) {
if (throwError) {
throw ConvertError.MissingParameter
}
}
else {
if let inputObject:T = input as? T {
output = inputObject
}
else if (throwError) {
throw ConvertError.WrongType
}
}
}
var myProperty:String
try readData(&myProperty, myJson["data"], true)
这会检查 属性 是否存在,并且它是正确的类型。如果一切顺利,myProperty 中的值会发生变化。
过了一会儿,我需要做一些改变。我制作了一个名为 properties 的 class,其中包含一个属性列表。这种类型的 class 有 2 个变量:originalProperties 和 modifiedProperties 这些 class 中的每个属性都是现在可选变量,专门用于跟踪用户更改了哪些属性。基本上它看起来像这样:
class Properties
{
var x:Int?
var y:Int?
}
现在当我运行这个:
try readData(&originalProperties.x, myJson["x"], false)
它不再起作用了。我查看了 another question,它解释了发生了什么。基本上 x 的值仍然是 nil (因为它是可选的),我将 nil 值传递到我的 readData 函数,所以模板类型设置不正确,这就是为什么它在 输入上失败的原因? T码.
幸运的是,我不用再拥有这样的创意功能了。我只能用这个:
originalProperties.x= obj["x"] as? Int
但是如果我需要的话,我会失去抛出错误的功能。
有没有人知道如何确保我的模板类型在其值为 nil 的情况下正确传递?我什至在另一个线程中读到我可能必须使用某种默认值闭包,但看看是否有办法解决这个问题会很有趣。
这里的主要问题是泛型 T
永远 自己 不知道它是否是 Optional
类型,这使得类型转换成功到 T
对于 T
实际上是 Optional<SomeType>
类型的情况来说很棘手。我们自己可以断言 T
是可选类型(检查 Mirror(reflecting: ...).displayStyle == .Optional
等),但这仍然不能立即解决到 T
的转换问题。相反,我们可以使用另一种方法,如下所示。
我们可以通过创建两个 readData(...)
函数来解决这个问题,一个采用可选的泛型 inout
参数,类型 U?
,另一个采用隐式 [=66] =] 泛型 inout
参数 U
(仅当 U?
函数无法使用时调用,因此隐式仅调用 non-optionals)。反过来,这两个函数是最小的,基本上只调用您的 "core" dataReader(..)
函数,我们在其中进行了调整,使 inout
泛型参数现在显式可选,即 T?
.
enum ConvertError: ErrorType {
case MissingParameter
case WrongType
}
/* optional inout parameter */
func readData<U>(inout output: U?, _ input: AnyObject?, _ throwError: Bool = true) throws {
try readDataCore(&output, input, throwError)
}
/* non-optional inout parameter */
func readData<U>(inout output: U, _ input: AnyObject?, _ throwError: Bool = true) throws {
var outputOpt : U? = output
try readDataCore(&outputOpt, input, throwError)
output = outputOpt!
/* you could use a guard-throw here for the unwrapping of 'outputOpt', but
note that 'outputOpt' is initialized with a non-nil value, and that it can
never become 'nil' in readDataHelper; so "safe" forced unwrapping here. */
}
/* "core" function */
func readDataCore<T>(inout output: T?, _ input: AnyObject?, _ throwError: Bool = true) throws
{
if (input == nil) {
if (throwError) {
throw ConvertError.MissingParameter
}
}
else {
if let inputObject: T = input as? T {
output = inputObject
}
else if (throwError) {
throw ConvertError.WrongType
}
}
}
当我们尝试这个时,我们发现我们现在得到了我们正在寻找的行为,即使作为 inout
参数发送的参数是 nil
或 Optional
。
示例 1:使用值为 nil
inout
参数
class Properties
{
var x:Int?
var y:Int?
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
do {
try readData(&originalProperties.x, myJson["data"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'originalProperties.x = 10', ok! */
// try some non-existing key 'foo'
do {
try readData(&originalProperties.x, myJson["foo"], true)
print("originalProperties.x = \(originalProperties.x ?? 0)")
} catch ConvertError.MissingParameter {
print("Missing parameter")
} catch ConvertError.WrongType {
print("Wrong type")
} catch {
print("Unknown error")
}
/* Prints: 'Missing parameter', ok! */
示例 2:使用可选的 inout
参数,但带有 non-optional 值
class Properties
{
var x:Int? = 1
var y:Int? = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */
示例 3:使用 non-optional inout
参数
class Properties
{
var x:Int = 1
var y:Int = 1
}
var myJson : [String:Int] = ["data":10]
var originalProperties = Properties()
// ...
/* Same results as for Example 1:
'originalProperties.x = 10' and 'Missing parameter' */