Swift 5.2新特性之Callable values of

2020-04-23  本文已影响0人  问问你是谁

我也不知道中文怎么翻译。还是直接看代码吧。

比如说我们有个加法容器类,定义如下:

struct Adder {
    var base: Int
    func applied(_ x: Int) -> Int {
        return base + x
    }
}

我们创建一个+3的加法器,然后计算10+3:

let add3 = Adder(base: 3)
let sum = add3.applied(10) // => 13

看起来很简单,代码也不多。但看这种情况:

let sum1 = adds.applied(adds.applied(adds.applied(10))) // => 19

嵌套几层,applied就出现几次,看着还是挺乱的。这个新特性就是用来解决这种冗余的。怎么做呢?这里引入了一个语法糖。让我们重新定义下Adder这个结构体:

struct Adder {
    var base: Int
    func callAsFunction(_ x: Int) -> Int {
        return base + x
    }
}

把原来做加法的函数名变为"callAsFunction"就可以了。然后我们就可以这样进行加法计算:

let add3 = Adder(base: 3)
let sum = add3(10) // => 13
let sum1 = add3(add3(add3(10)))  // => 19
// let sum1 = adds.applied(adds.applied(adds.applied(10)))

和原来比起来是不是更加简短了些,而且套用层数越多效果越明显。

可能很多人在开发iOS应用的时候遇不到太多这种一个方法多层嵌套的场景,所以对于这种语法糖性质的新特性感受不深。这里再借用一个官方给的关于深度神经网络的例子:

struct Model {
    var conv = Conv2D<Float>(filterShape: (5, 5, 3, 6))
    var maxPool = MaxPool2D<Float>(poolSize: (2, 2), strides: (2, 2))
    var flatten = Flatten<Float>()
    var dense = Dense<Float>(inputSize: 36 * 6, outputSize: 10)

    // 上面的四个变量都不用理,看这个方法
    func applied(to input: Tensor<Float>) -> Tensor<Float> {
        // 看这里的applied(to:)有多冗余
        return dense.applied(to: flatten.applied(to: maxPool.applied(to: conv.applied(to: input))))
    }
}

大家都知道,深度神经网络的特点就是有很多层,上一层的输出再作为下一层的输入,进行一个非线性变换之后输出再作为下一层的输入。于是我们看到上面的模型中返回的Tensor就是多层嵌套的结构。这时我们应用前面提到的新特性,去掉这个applied(to:),那这个嵌套会变得更加清晰可读。我们比照上面的例子,将上面Model里面的方法名用语法糖替换下:

    func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
        // 这个嵌套简单清晰多了
        return dense(flatten(maxPool(conv(input))))
    }

好吧,就是这么简单。

上一篇 下一篇

猜你喜欢

热点阅读