Swift3.0 Currying

作者: 晚雪浓情 | 来源:发表于2016-11-30 13:54 被阅读157次

    Currying是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.

    在某些情况下,你可能会用某个相同的参数重复调用某个方法,那么利用柯里化会使代码更易于维护,Ex:

    func sum(a: Int)(b: Int) -> Int {
        return a + b
    }
    var sumWithFive = sum(5)
    sumWithFive(b: 5)
    sumWithFive(b: 10)
    sumWithFive(b: 15)
    

    但是,Curring特性已经在Swift3.0中被remove了,The reason was:</br>
    Curried function declaration syntax func foo(x: Int)(y: Int) is of limited usefulness and creates a lot of language and implementation complexity. We should remove it.</br>
    (函数的 currying 特性的使用场景并不大,但他会增加很多语言的复杂性,所以需要删除它)

    �Well,你高兴就好,如果我们可能有需求要用到这个,怎么办?

    其实也是有类似的写法的:

     func caculate(_ num1: Int)->(Int)->Int{ return { num2 in num1 + num2} }
     let caculateOne = caculate(5)
     caculateOne(2)//7
     caculateOne(3)//8
    

    所以,昨天改造了一下之前写过的代码,写了一点闭包柯里化的东西(我知道函数的你们肯定都会写!):

    复制替换掉ViewController就可以直接用,但是肯定报错因为要换一张图片:]

    class ViewController: UIViewController
    {
        private lazy var postCardView:UIImageView =
        {
            let postCardView = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
            postCardView.center = self.view.center
            postCardView.image = UIImage(named: "1.jpg")
            postCardView.layer.cornerRadius = 5.0
            postCardView.clipsToBounds = true
            
            return postCardView
        }()
        
        override func viewDidLoad()
        {
            super.viewDidLoad()
          
            setUp()
        }
        
        func setUp()
        {
            view.layer.shadowColor = UIColor.black.cgColor
            view.layer.shadowOffset = CGSize(width: 0, height: 10)
            view.layer.shadowRadius = 10.0
            view.layer.shadowOpacity = 0.3
            
            view.addSubview(postCardView)
            view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panInCard(sender:))))
        }
        func panInCard(sender:UIPanGestureRecognizer)
        {
            let point = sender.location(in: view)
            
            let factor:(CGFloat)->(CGFloat)->CGFloat =
            {
                point in
                {
                    length in
                    min(1, max(-1, (point - length * 0.5) / length * 0.5))
                }
            }
    //        let factor:(CGFloat,CGFloat)->CGFloat = {  point,length in min(1, max(-1, (point - length * 0.5) / length * 0.5))  }
    
            let transformWithM34:(CGFloat)->(CGFloat)->(CGFloat)->CATransform3D =
            {
                m34 in
                {
                    xf in
                    {
                        yf in
                        var t = CATransform3DIdentity
                        t.m34 = m34
                        t = CATransform3DRotate(t, CGFloat(M_PI/9) * xf, 0, 1, 0)
                        t = CATransform3DRotate(t, CGFloat(M_PI/9) * yf, -1, 0, 0)
                        return t
                    }
                }
            }
    
            switch sender.state
            {
            case .changed:
                let (xFactor,yFactor) = (factor(point.x)(view.bounds.size.width),factor(point.y)(view.bounds.size.height))
                postCardView.layer.transform = transformWithM34(1.0 / -400)(xFactor)(yFactor)
            case .ended:
                UIView.animate(withDuration: 0.2, animations:{
                    self.postCardView.layer.transform = CATransform3DIdentity
                })
            default:
                break
            }
        }
    }
    

    通过对factor这个闭包的柯里化和正常写法可以发现,柯里化会很快增加代码的复杂程度,但同时又稍微提升了一点阅读性。

    然而对于下面的三参数闭包transformWithM34,代码就已经变得复杂多了。很多的括号看起来快比上if嵌套了。但是不知道亲爱的读者你们有没有发现,
    let transformWithM34:(CGFloat)->(CGFloat)->(CGFloat)->CATransform3D并没有指定形参名,也就是依次传入3个CGFloat类型的参数就可以收获一个CATransform3D的返回值。

    那么

    考虑参数的传入顺序,同样可以达到简化代码的目的,比如我们可以将比较固定的参数先传入,将变化的参数写在后面,这样当需要代码复用的时候,会比较方便。 举个🌰:

            let datePrint:(Int)->(Int)->(String)->Void =
            {
                month in
                print("\(month)月")
                return{
                    day in
                    print("\(day)日")
                    return{
                        action in print("\(action)")
                    }
                }
            }
            let actionPrint = datePrint(2016)(11)
            actionPrint("要出去玩")
            actionPrint("要回家")
    

    动作相对于某一天来说,时间是固定的,动作是变化的。我们如果想输出那一天的任何动作只需要actionPrint("xxx")就可以了。还是很方便的。
    ⬇️(本来是想写个年月日的例子,后来感觉可能没有这个有说服力,结果参数忘了改了,输出有点奇怪😂)⬇️

    Paste_Image.png

    最后想说的是。

    �最好不要在需要和很多UI控件交互的地方用这种多参数柯里化的闭包或者函数。。你懂得。
    这种代码适用范围估计也就是那些小巧或者即将变得小巧的工具方法了吧😊

    感谢您为阅读这篇文章付出了时间,谢谢。

    相关文章

      网友评论

        本文标题:Swift3.0 Currying

        本文链接:https://www.haomeiwen.com/subject/agzzpttx.html