apply 订阅
apply是一个英文单词,动词,意思是“应用;申请;涂,敷;适用;请求”。 展开全文
apply是一个英文单词,动词,意思是“应用;申请;涂,敷;适用;请求”。
信息
外文名
apply
词    性
动词
apply单词发音
英 [əˈplaɪ] 美 [əˈplaɪ]
收起全文
精华内容
下载资源
问答
  • Kotlin系列之let、with、run、apply、also函数的使用

    万次阅读 多人点赞 2017-12-12 21:59:53
    标签: Kotlin 常用技巧 目录: 一、回调函数的Kotin的lambda的简化 ...七、let,with,run,apply,also函数区别 简述: 相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说

    标签: Kotlin      常用技巧


    目录:

    简述:

    相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够优雅的代码。在Kotlin中的源码标准库(Standard.kt)中提供了一些Kotlin扩展的内置函数可以优化kotlin的编码。Standard.kt是Kotlin库的一部分,它定义了一些基本函数。 这个源代码文件虽然一共不到50行代码,但是这些函数功能都非常强大。


    一、回调函数的Kotin的lambda的简化

    在Kotlin中对Java中的一些的接口的回调做了一些优化,可以使用一个lambda函数来代替。可以简化写一些不必要的嵌套回调方法。但是需要注意:在lambda表达式,只支持单抽象方法模型,也就是说设计的接口里面只有一个抽象的方法,才符合lambda表达式的规则,多个回调方法不支持。

    • 1、用Java代码实现一个接口的回调。

       mView.setEventListener(new ExamPlanHomeEventListener(){
       
          public void onSuccess(Data data){
            //todo
          }
       
       });
      
      
    • 2、在Kotlin中的实现一个接口的回调,不使用lambda表达式(这种方式非常适用于kotlin中对于一个接口中含有多个回调方法)。

      
      mView.setEventListener(object: ExamPlanHomeEventListener{
           
          public void onSuccess(Data data){
            //todo
          }
           
      });
      
    • 3、如果在Kotlin中的对于接口只有一个回调的方法,就符合使用lambda函数,我们可以把以上代码简化成这样。

      mView.setEventListener({
         data: Data ->
         //todo
      })
      
      //或者可以直接省略Data,借助kotlin的智能类型推导
      
      mView.setEventListener({
         data ->
         //todo
      })
      
    • 4、如果以上代码中的data参数没有使用到的话,可以直接把data去掉

      mView.setEventListener({
        //todo
      
      })
      
    • 5、以上代码还可以做个调整,由于setEventListener函数最后一个参数是一个函数的话,可以直接把括号的实现提到圆括号外面

      mView.setEventListener(){
         //todo
      }
      
    • 6、由于setEventListener这个函数只有一个参数,可以直接省略圆括号

      mView.setEventListener{
        //todo
      }
      

    二、内联扩展函数之let

    let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。
    
    • 1、let函数的使用的一般结构
    object.let{
       it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法
       ...
    }
    
    //另一种用途 判断object为null的操作
    object?.let{//表示object不为null的条件下,才会去执行let函数体
       it.todo()
    }
    
    • 2、let函数底层的inline扩展函数+lambda结构
       @kotlin.internal.InlineOnly
    public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
    
    • 3、let函数inline结构的分析

      从源码let函数的结构来看它是只有一个lambda函数块block作为参数的函数,调用T类型对象的let函数,则该对象为函数的参数。在函数块内可以通过 it 指代该对象。返回值为函数块的最后一行或指定return表达式。

    • 4、let函数的kotlin和Java转化

       //kotlin
       
       fun main(args: Array<String>) {
          val result = "testLet".let {
              println(it.length)
              1000
          }
          println(result)
       }
       
       //java
       
       public final class LetFunctionKt {
         public static final void main(@NotNull String[] args) {
            Intrinsics.checkParameterIsNotNull(args, "args");
            String var2 = "testLet";
            int var4 = var2.length();
            System.out.println(var4);
            int result = 1000;
            System.out.println(result);
         }
      }
      
       
      
    • 5、let函数适用的场景

      场景一: 最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理。

      场景二: 然后就是需要去明确一个变量所处特定的作用域范围内可以使用

    • 6、let函数使用前后的对比

      没有使用let函数的代码是这样的,看起来不够优雅

      mVideoPlayer?.setVideoView(activity.course_video_view)
      	mVideoPlayer?.setControllerView(activity.course_video_controller_view)
      	mVideoPlayer?.setCurtainView(activity.course_video_curtain_view)
      

    使用let函数后的代码是这样的

    ```
    mVideoPlayer?.let {
    	   it.setVideoView(activity.course_video_view)
    	   it.setControllerView(activity.course_video_controller_view)
    	   it.setCurtainView(activity.course_video_curtain_view)
    }
    	
    ```
    

    三、内联函数之with

    • 1、with函数使用的一般结构

       with(object){
         //todo
       }
      
    • 2、with函数底层的inline扩展函数+lambda结构

      @kotlin.internal.InlineOnly
      public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
      
      
    • 3、with函数inline结构的分析

    with函数和前面的几个函数使用方式略有不同,因为它不是以扩展的形式存在的。它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象。返回值为函数块的最后一行或指定return表达式。

    可以看出with函数是接收了两个参数,分别为T类型的对象receiver和一个lambda函数块,所以with函数最原始样子如下:

    ```
    
    val result = with(user, {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        })
    ```
    

    但是由于with函数最后一个参数是一个函数,可以把函数提到圆括号的外部,所以最终with函数的调用形式如下:

    ```
    val result = with(user) {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        }
    ```
    
    • 4、with函数的kotlin和Java转化

      //kotlin
      
      fun main(args: Array<String>) {
          val user = User("Kotlin", 1, "1111111")
      
          val result = with(user) {
              println("my name is $name, I am $age years old, my phone number is $phoneNum")
              1000
          }
          println("result: $result")
      }
      
      //java
      
       public static final void main(@NotNull String[] args) {
            Intrinsics.checkParameterIsNotNull(args, "args");
            User user = new User("Kotlin", 1, "1111111");
            String var4 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
            System.out.println(var4);
            int result = 1000;
            String var3 = "result: " + result;
            System.out.println(var3);
         }
      
      
    • 5、with函数的适用的场景

    适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上

    • 6、with函数使用前后的对比

    没有使用kotlin中的实现

    ```
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
    
       ArticleSnippet item = getItem(position);
    		if (item == null) {
    			return;
    		}
    		holder.tvNewsTitle.setText(StringUtils.trimToEmpty(item.titleEn));
    		holder.tvNewsSummary.setText(StringUtils.trimToEmpty(item.summary));
    		String gradeInfo = "难度:" + item.gradeInfo;
    		String wordCount = "单词数:" + item.length;
    		String reviewNum = "读后感:" + item.numReviews;
    		String extraInfo = gradeInfo + " | " + wordCount + " | " + reviewNum;
    		holder.tvExtraInfo.setText(extraInfo);
    		...
    }
    
    ```
    

    kotlin的实现

    ```
    override fun onBindViewHolder(holder: ViewHolder, position: Int){
       val item = getItem(position)?: return
       
       with(item){
       
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
    	   holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
    	   holder.tvExtraInf.text = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
       
       }
    
    }
    
    ```
    

    四、内联扩展函数之run

    • 1、run函数使用的一般结构

      object.run{
      //todo
      }
      
    • 2、run函数的inline+lambda结构

      @kotlin.internal.InlineOnly
      public inline fun <T, R> T.run(block: T.() -> R): R = block()
      
    • 3、run函数的inline结构分析

      run函数实际上可以说是let和with两个函数的结合体,run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式。

    • 4、run函数的kotlin和Java转化

      //kotlin
      
      fun main(args: Array<String>) {
          val user = User("Kotlin", 1, "1111111")
      
          val result = user.run {
              println("my name is $name, I am $age years old, my phone number is $phoneNum")
              1000
          }
          println("result: $result")
      }
      
      //java
      
        public static final void main(@NotNull String[] args) {
            Intrinsics.checkParameterIsNotNull(args, "args");
            User user = new User("Kotlin", 1, "1111111");
            String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
            System.out.println(var5);
            int result = 1000;
            String var3 = "result: " + result;
            System.out.println(var3);
         }
      
      
    • 5、run函数的适用场景

    适用于let,with函数任何场景。因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理

    • 6、run函数使用前后的对比

    还是借助上个例子kotlin代码

    ```
    override fun onBindViewHolder(holder: ViewHolder, position: Int){
       val item = getItem(position)?: return
       
       with(item){
       
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
    	   holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
    	   holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
       
       }
    
    }
    ```
    

    使用run函数后的优化

    ```
    override fun onBindViewHolder(holder: ViewHolder, position: Int){
       
      getItem(position)?.run{
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
    	   holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
    	   holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
       
       }
    
    }
    
    ```
    

    五、内联扩展函数之apply

    • 1、apply函数使用的一般结构

      object.apply{
      //todo
      }
      
    • 2、apply函数的inline+lambda结构

      @kotlin.internal.InlineOnly
      public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
      
    • 3、apply函数的inline结构分析

    从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。

    • 4、apply函数的kotlin和Java转化

      //kotlin
      
      fun main(args: Array<String>) {
          val user = User("Kotlin", 1, "1111111")
      
          val result = user.apply {
              println("my name is $name, I am $age years old, my phone number is $phoneNum")
              1000
          }
          println("result: $result")
      }
      
      //java
      
      public final class ApplyFunctionKt {
         public static final void main(@NotNull String[] args) {
            Intrinsics.checkParameterIsNotNull(args, "args");
            User user = new User("Kotlin", 1, "1111111");
            String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
            System.out.println(var5);
            String var3 = "result: " + user;
            System.out.println(var3);
         }
      }
      
      
    • 5、apply函数的适用场景

    整体作用功能和run函数很像,唯一不同点就是它返回的值是对象本身,而run函数是一个闭包形式返回,返回的是最后一行的值。正是基于这一点差异它的适用场景稍微与run函数有点不一样。apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到。

    • 6、apply函数使用前后的对比

    没有使用apply函数的代码是这样的,看起来不够优雅

    ```
    mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null)
            mSheetDialogView.course_comment_tv_label.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_score.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_cancel.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_confirm.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_seek_bar.max = 10
            mSheetDialogView.course_comment_seek_bar.progress = 0
    ```
    

    使用apply函数后的代码是这样的

    ```
    mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null).apply{
       course_comment_tv_label.paint.isFakeBoldText = true
       course_comment_tv_score.paint.isFakeBoldText = true
       course_comment_tv_cancel.paint.isFakeBoldText = true
       course_comment_tv_confirm.paint.isFakeBoldText = true
       course_comment_seek_bar.max = 10
       course_comment_seek_bar.progress = 0
    
    }
    
    ```
    

    多层级判空问题

    ```
    	if (mSectionMetaData == null || mSectionMetaData.questionnaire == null || mSectionMetaData.section == null) {
    			return;
    		}
    		if (mSectionMetaData.questionnaire.userProject != null) {
    			renderAnalysis();
    			return;
    		}
    		if (mSectionMetaData.section != null && !mSectionMetaData.section.sectionArticles.isEmpty()) {
    			fetchQuestionData();
    			return;
    		}
    ```
    

    kotlin的apply函数优化

    ```
    mSectionMetaData?.apply{
    
    //mSectionMetaData不为空的时候操作mSectionMetaData
    
    }?.questionnaire?.apply{
    
    //questionnaire不为空的时候操作questionnaire
    
    }?.section?.apply{
    
    //section不为空的时候操作section
    
    }?.sectionArticle?.apply{
    
    //sectionArticle不为空的时候操作sectionArticle
    
    }
    
    ```
    

    六、内联扩展函数之also

    • 1、also函数使用的一般结构

      object.also{
      //todo
      }
      
    • 2、also函数的inline+lambda结构

      @kotlin.internal.InlineOnly
      

    @SinceKotlin(“1.1”)
    public inline fun T.also(block: (T) -> Unit): T { block(this); return this }
    ```

    • 3、also函数的inline结构分析

    also函数的结构实际上和let很像唯一的区别就是返回值的不一样,let是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值。而also函数返回的则是传入对象的本身

    • 4、also函数编译后的class文件

      //kotlin
      
      fun main(args: Array<String>) {
          val result = "testLet".also {
              println(it.length)
              1000
          }
          println(result)
      }
      
      //java
      
      public final class AlsoFunctionKt {
         public static final void main(@NotNull String[] args) {
            Intrinsics.checkParameterIsNotNull(args, "args");
            String var2 = "testLet";
            int var4 = var2.length();
            System.out.println(var4);
            System.out.println(var2);
         }
      }
      
    • 5、also函数的适用场景

      适用于let函数的任何场景,also函数和let很像,只是唯一的不同点就是let函数最后的返回值是最后一行的返回值而also函数的返回值是返回当前的这个对象。一般可用于多个扩展函数链式调用

    • 6、also函数使用前后的对比

      和let函数类似

    七、let,with,run,apply,also函数区别

    通过以上几种函数的介绍,可以很方便优化kotlin中代码编写,整体看起来几个函数的作用很相似,但是各自又存在着不同。使用的场景有相同的地方比如run函数就是let和with的结合体。下面一张表格可以清晰对比出他们的不同之处。

    函数名 定义inline的结构 函数体内使用的对象 返回值 是否是扩展函数 适用的场景
    let fun <T, R> T.let(block: (T) -> R): R = block(this) it指代当前对象 闭包形式返回 适用于处理不为null的操作场景
    with fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() this指代当前对象或者省略 闭包形式返回 适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上
    run fun <T, R> T.run(block: T.() -> R): R = block() this指代当前对象或者省略 闭包形式返回 适用于let,with函数任何场景。
    apply fun T.apply(block: T.() -> Unit): T { block(); return this } this指代当前对象或者省略 返回this 1、适用于run函数的任何场景,一般用于初始化一个对象实例的时候,操作对象属性,并最终返回这个对象。
    2、动态inflate出一个XML的View的时候需要给View绑定数据也会用到.
    3、一般可用于多个扩展函数链式调用
    4、数据model多层级包裹判空处理的问题
    also fun T.also(block: (T) -> Unit): T { block(this); return this } it指代当前对象 返回this 适用于let函数的任何场景,一般可用于多个扩展函数链式调用
    1

    欢迎关注Kotlin开发者联盟,这里有最新Kotlin技术文章,每周会不定期翻译一篇Kotlin国外技术文章。如果你也喜欢Kotlin,欢迎加入我们~~~

    Kotlin系列文章,欢迎查看:

    Kotlin邂逅设计模式系列:

    数据结构与算法系列:

    翻译系列:

    原创系列:

    Effective Kotlin翻译系列

    实战系列:

    展开全文
  • 理解Angular中的$apply()以及$digest()

    万次阅读 多人点赞 2014-08-20 13:49:13
    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑。而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的。这篇文章旨在解释$apply()和$digest()是什么,以及在...

    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑。而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的。这篇文章旨在解释$apply()和$digest()是什么,以及在日常的编码中如何应用它们。

     

    探索$apply()和$digest()

    AngularJS提供了一个非常酷的特性叫做双向数据绑定(Two-way Data Binding),这个特性大大简化了我们的代码编写方式。数据绑定意味着当View中有任何数据发生了变化,那么这个变化也会自动地反馈到scope的数据上,也即意味着scope模型会自动地更新。类似地,当scope模型发生变化时,view中的数据也会更新到最新的值。那么AngularJS是如何做到这一点的呢?当你写下表达式如{{ aModel }}时,AngularJS在幕后会为你在scope模型上设置一个watcher,它用来在数据发生变化的时候更新view。这里的watcher和你会在AngularJS中设置的watcher是一样的:

     

    $scope.$watch('aModel', function(newValue, oldValue) {
      //update the DOM with newValue
    });

     

    传入到$watch()中的第二个参数是一个回调函数,该函数在aModel的值发生变化的时候会被调用。当aModel发生变化的时候,这个回调函数会被调用来更新view这一点不难理解,但是,还存在一个很重要的问题!AngularJS是如何知道什么时候要调用这个回调函数呢?换句话说,AngularJS是如何知晓aModel发生了变化,才调用了对应的回调函数呢?它会周期性的运行一个函数来检查scope模型中的数据是否发生了变化吗?好吧,这就是$digest循环的用武之地了。

     

    在$digest循环中,watchers会被触发。当一个watcher被触发时,AngularJS会检测scope模型,如何它发生了变化那么关联到该watcher的回调函数就会被调用。那么,下一个问题就是$digest循环是在什么时候以各种方式开始的?

     

    在调用了$scope.$digest()后,$digest循环就开始了。假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用$digest()来触发一轮$digest循环。当$digest循环开始后,它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容(译注:诸如{{ aModel }})会被更新。除了ng-click指令,还有一些其它的built-in指令以及服务来让你更改models(比如ng-model,$timeout等)和自动触发一次$digest循环。

     

    目前为止还不错!但是,有一个小问题。在上面的例子中,AngularJS并不直接调用$digest(),而是调用$scope.$apply(),后者会调用$rootScope.$digest()。因此,一轮$digest循环在$rootScope开始,随后会访问到所有的children scope中的watchers。

     

    现在,假设你将ng-click指令关联到了一个button上,并传入了一个function名到ng-click上。当该button被点击时,AngularJS会将此function包装到一个wrapping function中,然后传入到$scope.$apply()。因此,你的function会正常被执行,修改models(如果需要的话),此时一轮$digest循环也会被触发,用来确保view也会被更新。

     

    Note: $scope.$apply()会自动地调用$rootScope.$digest()。$apply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮$digest循环。第二种会不接受任何参数,只是触发一轮$digest循环。我们马上会看到为什么第一种形式更好。

     

    什么时候手动调用$apply()方法?

    如果AngularJS总是将我们的代码wrap到一个function中并传入$apply(),以此来开始一轮$digest循环,那么什么时候才需要我们手动地调用$apply()方法呢?实际上,AngularJS对此有着非常明确的要求,就是它只负责对发生于AngularJS上下文环境中的变更会做出自动地响应(即,在$apply()方法中发生的对于models的更改)。AngularJS的built-in指令就是这样做的,所以任何的model变更都会被反映到view中。但是,如果你在AngularJS上下文之外的任何地方修改了model,那么你就需要通过手动调用$apply()来通知AngularJS。这就像告诉AngularJS,你修改了一些models,希望AngularJS帮你触发watchers来做出正确的响应。

     

    比如,如果你使用了JavaScript中的setTimeout()来更新一个scope model,那么AngularJS就没有办法知道你更改了什么。这种情况下,调用$apply()就是你的责任了,通过调用它来触发一轮$digest循环。类似地,如果你有一个指令用来设置一个DOM事件listener并且在该listener中修改了一些models,那么你也需要通过手动调用$apply()来确保变更会被正确的反映到view中。

     

    让我们来看一个例子。加入你有一个页面,一旦该页面加载完毕了,你希望在两秒钟之后显示一条信息。你的实现可能是下面这个样子的:

     

    HTML:

     

    <body ng-app="myApp">
      <div ng-controller="MessageController">
        Delayed Message: {{message}}
      </div>  
    </body>

     

     

    JavaScript:
    /* What happens without an $apply() */
        
        angular.module('myApp',[]).controller('MessageController', function($scope) {
        
          $scope.getMessage = function() {
            setTimeout(function() {
              $scope.message = 'Fetched after 3 seconds';
              console.log('message:'+$scope.message);
            }, 2000);
          }
          
          $scope.getMessage();
        
        });

     

    通过运行这个例子,你会看到过了两秒钟之后,控制台确实会显示出已经更新的model,然而,view并没有更新。原因也许你已经知道了,就是我们忘了调用$apply()方法。因此,我们需要修改getMessage(),如下所示:

     

     

    /* What happens with $apply */ 
    angular.module('myApp',[]).controller('MessageController', function($scope) {
        
          $scope.getMessage = function() {
            setTimeout(function() {
              $scope.$apply(function() {
                //wrapped this within $apply
                $scope.message = 'Fetched after 3 seconds'; 
                console.log('message:' + $scope.message);
              });
            }, 2000);
          }
          
          $scope.getMessage();
        
        });

     

     

    如果你运行了上面的例子,你会看到view在两秒钟之后也会更新。唯一的变化是我们的代码现在被wrapped到了$scope.$apply()中,它会自动触发$rootScope.$digest(),从而让watchers被触发用以更新view。

     

    Note:顺便提一下,你应该使用$timeout service来代替setTimeout(),因为前者会帮你调用$apply(),让你不需要手动地调用它。

     

    而且,注意在以上的代码中你也可以在修改了model之后手动调用没有参数的$apply(),就像下面这样:

     

    $scope.getMessage = function() {
      setTimeout(function() {
        $scope.message = 'Fetched after two seconds';
        console.log('message:' + $scope.message);
        $scope.$apply(); //this triggers a $digest
      }, 2000);
    };

     

    以上的代码使用了$apply()的第二种形式,也就是没有参数的形式。需要记住的是你总是应该使用接受一个function作为参数的$apply()方法。这是因为当你传入一个function到$apply()中的时候,这个function会被包装到一个try…catch块中,所以一旦有异常发生,该异常会被$exceptionHandler service处理。

     

    $digest循环会运行多少次?

    当一个$digest循环运行时,watchers会被执行来检查scope中的models是否发生了变化。如果发生了变化,那么相应的listener函数就会被执行。这涉及到一个重要的问题。如果listener函数本身会修改一个scope model呢?AngularJS会怎么处理这种情况?

     

    答案是$digest循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models发生了变化。这就是脏检查(Dirty Checking),它用来处理在listener函数被执行时可能引起的model变化。因此,$digest循环会持续运行直到model不再发生变化,或者$digest循环的次数达到了10次。因此,尽可能地不要在listener函数中修改model。

     

    Note: $digest循环最少也会运行两次,即使在listener函数中并没有改变任何model。正如上面讨论的那样,它会多运行一次来确保models没有变化。

     

    结语

    我希望这篇文章解释清楚了$apply和$digest。需要记住的最重要的是AngularJS是否能检测到你对于model的修改。如果它不能检测到,那么你就需要手动地调用$apply()。

     

     

    原文地址

    http://www.sitepoint.com/understanding-angulars-apply-digest/

     

     

     

     

     

     

    展开全文
  • 【Python】Pandas 的 apply 函数使用示例

    万次阅读 多人点赞 2016-11-03 11:25:42
    apply 是 pandas 库的一个很重要的函数,多和 groupby 函数一起用,也可以直接用于 DataFrame 和 Series 对象。主要用于数据聚合运算,可以很方便的对分组进行现有的运算和自定义的运算。 数据集 使用的数据...

    applypandas 库的一个很重要的函数,多和 groupby 函数一起用,也可以直接用于 DataFrameSeries 对象。主要用于数据聚合运算,可以很方便的对分组进行现有的运算和自定义的运算。
    在这里插入图片描述


    数据集

    使用的数据集是美国人口普查的数据,可以从这里下载,里面包含了CSV数据文件和PDF说明文件,说明文件里解释了每个变量的意义。

    数据大致是这个样子:

    美国人口普查数据
    *美国人口普查数据*

    问题

    1. 以每个州人口最多的 3 个县的人口总和为这个州人口的衡量标准,哪 3 个州人口最多?
    2. 在 2010 年至 2015 年间人口变化幅度最大的是哪个县?

    分析

    1. 先按州分组,再对每个州内的县进行排序选出人口最多的 3 个县求和,作为每个州的人口数,最后排序。
    2. 对于每个县,计算 2010-2015 年的人口数的最大值和最小值,求出差值即变化幅度,再对差值进行排序找出变化幅度最大的县。

    代码

    问题1

    census_df = pd.read_csv('census.csv')
    only_county = census_df[census_df['SUMLEV'] == 50]
    
    
    def top(df, n=3, column='CENSUS2010POP'):
        return df.sort_values(column, ascending=False)[:n]['CENSUS2010POP'].sum()
    
    
    grouped = only_county[['STNAME', 'CTYNAME', 'CENSUS2010POP']].groupby('STNAME').apply(top)
    grouped.sort_values(ascending=False)[:3].index.tolist()
    

    输出:
    在这里插入图片描述

    问题2

    census_df = pd.read_csv('census.csv')
    only_county = census_df[census_df['SUMLEV'] == 50]
    
    
    def get_change(row):
        pop_year = row[['POPESTIMATE2010', 
    					'POPESTIMATE2011', 
    					'POPESTIMATE2012', 
    					'POPESTIMATE2013', 
    					'POPESTIMATE2014', 
    					'POPESTIMATE2015']]
        return pop_year.max() - pop_year.min()
    
    
    only_county.loc[only_county.apply(get_change, axis=1).argmax()]['CTYNAME']
    

    输出:

    这里写图片描述


    END

    展开全文
  • pandas apply() 函数用法

    万次阅读 多人点赞 2019-08-22 10:00:46
    函数式编程,包括函数式编程思维,当然是一个很复杂的话题,但对今天介绍的 apply() 函数,只需要理解:函数作为一个对象,能作为参数传递给其它参数,并且能作为函数的返回值。 函数作为对象能带来代码风格巨大的...

    理解 pandas 的函数,要对函数式编程有一定的概念和理解。函数式编程,包括函数式编程思维,当然是一个很复杂的话题,但对今天介绍的 apply() 函数,只需要理解:函数作为一个对象,能作为参数传递给其它参数,并且能作为函数的返回值。

    函数作为对象能带来代码风格巨大的改变。举一个例子,有一个包含 1 到 10 的 list,从其中找出能被 3 整除的数字。用传统的方法:

    def can_divide_by_three(number):
        if number % 3 == 0:
            return True
        else:
            return False
    
    selected_numbers = []
    for number in range(1, 11):
        if can_divide_by_three(number):
            selected_numbers.append(number)
    

    循环是不可少的,因为 can_divide_by_three() 函数只用一次,可以用 lambda 表达式简化:

    divide_by_three = lambda x : True if x % 3 == 0 else False
    
    selected_numbers = []
    for number in range(1, 11):
        if divide_by_three(item):
            selected_numbers.append(item)
    

    这个就是传统编程思维方式,如果用函数式的编程方法呢,我们可以这样想:从一个 list 中取出特定规则的数字,能不能只关注和设置这个规则,循环这种事情交给编程语言去处理呢?当然可以。当编程人员只关心规则(规则可能是一个条件,或者由某一个 function 来定义),代码将大大简化,可读性也更强。

    Python 语言提供 filter() 函数,语法如下:

    filter(function, sequence)
    

    filter() 函数的功能:对 sequence 中的 item 依次执行 function(item),将结果为 True 的 item 组成一个 List/String/Tuple(取决于 sequence 的类型)并返回。有了这个函数,上面的代码可以简化为:

    divide_by_three = lambda x : True if x % 3 == 0 else False
    selected_numbers = filter(divide_by_three, range(1, 11))
    

    将 lambda 表达式放在语句中,代码简化到只需要一句话就够了:

    selected_numbers = filter(lambda x: x % 3 == 0, range(1, 11))
    

    Series.apply()

    回到主题, pandas 的 apply() 函数可以作用于 Series 或者整个 DataFrame,功能也是自动遍历整个 Series 或者 DataFrame, 对每一个元素运行指定的函数。

    举一个例子,现在有这样一组数据,学生的考试成绩:

      Name Nationality  Score
       张           汉    400
       李           回    450
       王           汉    460
    

    如果民族不是汉族,则总分在考试分数上再加 5 分,现在需要用 pandas 来做这种计算,我们在 Dataframe 中增加一列。当然如果只是为了得到结果, numpy.where() 函数更简单,这里主要为了演示 Series.apply() 函数的用法。

    import pandas as pd
    
    df = pd.read_csv("studuent-score.csv")
    df['ExtraScore'] = df['Nationality'].apply(lambda x : 5 if x != '汉' else 0)
    df['TotalScore'] = df['Score'] + df['ExtraScore']
    

    对于 Nationality 这一列, pandas 遍历每一个值,并且对这个值执行 lambda 匿名函数,将计算结果存储在一个新的 Series 中返回。上面代码在 jupyter notebook 中显示的结果如下:

      Name Nationality  Score  ExtraScore  TotalScore
    0    张           汉    400           0         400
    1    李           回    450           5         455
    2    王           汉    460           0         460
    

    apply() 函数当然也可执行 python 内置的函数,比如我们想得到 Name 这一列字符的个数,如果用 apply() 的话:

    df['NameLength'] = df['Name'].apply(len)
    

    DataFrame.apply()

    DataFrame.apply() 函数则会遍历每一个元素,对元素运行指定的 function。比如下面的示例:

    import pandas as pd
    import numpy as np
    
    matrix = [
        [1,2,3],
        [4,5,6],
        [7,8,9]
    ]
    
    df = pd.DataFrame(matrix, columns=list('xyz'), index=list('abc'))
    df.apply(np.square)
    

    对 df 执行 square() 函数后,所有的元素都执行平方运算:

        x   y   z
    a   1   4   9
    b  16  25  36
    c  49  64  81
    

    如果只想 apply() 作用于指定的行和列,可以用行或者列的 name 属性进行限定。比如下面的示例将 x 列进行平方运算:

    df.apply(lambda x : np.square(x) if x.name=='x' else x)
    
        x  y  z
    a   1  2  3
    b  16  5  6
    c  49  8  9
    

    下面的示例对 x 和 y 列进行平方运算:

    df.apply(lambda x : np.square(x) if x.name in ['x', 'y'] else x)
    
        x   y  z
    a   1   4  3
    b  16  25  6
    c  49  64  9
    

    下面的示例对第一行 (a 标签所在行)进行平方运算:

    df.apply(lambda x : np.square(x) if x.name == 'a' else x, axis=1)
    

    默认情况下 axis=0 表示按列,axis=1 表示按行。

    apply() 计算日期相减示例

    平时我们会经常用到日期的计算,比如要计算两个日期的间隔,比如下面的一组关于 wbs 起止日期的数据:

        wbs   date_from     date_to
      job1  2019-04-01  2019-05-01
      job2  2019-04-07  2019-05-17
      job3  2019-05-16  2019-05-31
      job4  2019-05-20  2019-06-11
    

    假定要计算起止日期间隔的天数。比较简单的方法就是两列相减(datetime 类型):

    import pandas as pd
    import datetime as dt
    
    wbs = {
        "wbs": ["job1", "job2", "job3", "job4"],
        "date_from": ["2019-04-01", "2019-04-07", "2019-05-16","2019-05-20"],
        "date_to": ["2019-05-01", "2019-05-17", "2019-05-31", "2019-06-11"]
    }
    
    df = pd.DataFrame(wbs)
    df['elpased' = df['date_to'].apply(pd.to_datetime) -   
                   df['date_from'].apply(pd.to_datetime)
    

    apply() 函数将 date_fromdate_to 两列转换成 datetime 类型。我们 print 一下 df:

        wbs   date_from     date_to elapsed
    0  job1  2019-04-01  2019-05-01 30 days
    1  job2  2019-04-07  2019-05-17 40 days
    2  job3  2019-05-16  2019-05-31 15 days
    3  job4  2019-05-20  2019-06-11 22 days
    

    日期间隔已经计算出来,但后面带有一个单位 days,这是因为两个 datetime 类型相减,得到的数据类型是 timedelta64,如果只要数字,还需要使用 timedeltadays 属性转换一下。

    elapsed= df['date_to'].apply(pd.to_datetime) -
        df['date_from'].apply(pd.to_datetime)
    df['elapsed'] = elapsed.apply(lambda x : x.days)
    

    使用 DataFrame.apply() 函数也能达到同样的效果,我们需要先定义一个函数 get_interval_days() 函数的第一列是一个 Series 类型的变量,执行的时候,依次接收 DataFrame 的每一行。

    import pandas as pd
    import datetime as dt
    
    def get_interval_days(arrLike, start, end):   
        start_date = dt.datetime.strptime(arrLike[start], '%Y-%m-%d')
        end_date = dt.datetime.strptime(arrLike[end], '%Y-%m-%d') 
    
        return (end_date - start_date).days
    
    
    wbs = {
        "wbs": ["job1", "job2", "job3", "job4"],
        "date_from": ["2019-04-01", "2019-04-07", "2019-05-16","2019-05-20"],
        "date_to": ["2019-05-01", "2019-05-17", "2019-05-31", "2019-06-11"]
    }
    
    df = pd.DataFrame(wbs)
    df['elapsed'] = df.apply(
        get_interval_days, axis=1, args=('date_from', 'date_to'))
    

    参考

    Pandas的Apply函数——Pandas中最好用的函数

    展开全文
  • Pandas对每个分组应用apply函数

    万次阅读 2020-05-01 16:02:57
    Pandas对每个分组应用apply函数Pandas的apply函数概念(图解)实例1:怎样对数值按分组的归一化实例2:怎样取每个分组的TOPN数据 Pandas的apply函数概念(图解) 实例1:怎样对数值按分组的归一化 实例2:...
  • Python apply函数

    万次阅读 2019-07-05 21:03:38
    Python apply函数 1、介绍 apply函数是pandas里面所有函数中自由度最高的函数。该函数如下: DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds) 该函数最有用的是第...
  • Pandas的Apply函数——Pandas中最好用的函数

    万次阅读 多人点赞 2018-02-22 18:22:04
    对于数据处理来说,有好多有用的相关操作的函数,但是我认为其中最好用的函数是下面这个函数: apply函数 apply函数是`pandas`里面所有函数中自由度最高的函数。该函数如下: DataFrame.apply(func, axis=0, ...
  • Cross Apply 与 Outer Apply 的区别

    千次阅读 2018-05-11 22:22:38
    Cross Apply 与 Outer Apply 的区别,就像是 Inner join 与 Outer Join 的区别。 Inner Join 如果两边的表,无论是 Left Table, 或者是 Right Table, 做了限制,都会被应用到两边去,即一方的结果影响了另一方的...
  • SQL 关于apply的两种形式cross apply 和 outer apply 原地址:http://www.cnblogs.com/Leo_wl/archive/2013/04/02/2997012.html apply有两种形式: cross apply 和 outer apply 先看看语法:  ...
  • apply call

    2018-08-01 15:29:09
    apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.  Function.apply(obj,args)方法能接收两个参数  obj:这个对象将代替Function类里this对象  args:这个是数组,它将作为参数传给Function(args--...
  • kubectl applyIn this post, we’ll explore how the kubectl apply command works internally. Which will give you a better understanding of how kubernetes works under the hood and make you stand out as a ...
  • SQL Server数据库操作中,在2005以上的版本新增加了一个APPLY表运算符的功能。新增的APPLY表运算符把右表表达式应用到左表表达式中的每一行。它不像JOIN那样先计算那个表表达式都可以,APPLY必选先逻辑地计算左...
  • python----多进程 apply(), apply_async()

    万次阅读 多人点赞 2018-12-20 15:14:40
    python 大法好 apply(), apply_async() 今天早上起来学习的三个东西, 这里写写个, 本来想写在上一篇join()的学习记录里面的, 因为他们有点类似, 都可以阻塞程序, 但是不知道为什么我又突然想分开写了… … 先说一下...
  • 进程池Pool中的apply方法与apply_async的区别 apply方法是阻塞的。 意思就是等待当前子进程执行完毕后,在执行下一个进程。 示例apply的应用方法 import time from multiprocessing import Pool def run(msg): ...
  • DataFrame.apply与GroupBy.apply的用法

    千次阅读 2018-11-05 11:46:19
    DataFrame.apply的用法 DataFrame.apply操作的对象是DataFrame的一行或者一列,通过axis来指定行或者列,最终返回的类型取决于apply函数操作的结果。 对行进行操作 添加新行 df = pd.DataFrame({'A': [1, 1, 1, 1, 2...
  • Outer Apply 和 Cross Apply 的妙用

    千次阅读 2019-06-07 07:42:52
    我们当然可以使用 row_number取 rid =1来实现,但某些情况下 outer apply或 cross apply或许会更方便。 USE tempdb GO IF OBJECT_ID('stu') IS NOT NULL DROP TABLE stu GO CREATE TABLE s...
  • python进程池applyapply_async的区别

    万次阅读 2018-07-17 16:48:56
    apply方法是阻塞的。 意思就是等待当前子进程执行完毕后,在执行下一个进程。 例如:     执行结果如下:     因为apply是阻塞的,所以进入子进程执行后,等待当前子进程执行完毕,在继续执行...
  • 一、学习this的指向问题 二、call和apply的特点与区别 三、模拟实现一个call 四、bind的功能 五、结尾 思考题+导图+示例代码,让你轻松掌握!
  • R语言_apply系列函数

    2015-08-18 17:36:25
    apply
  • SQL Server 2005 新增 cross apply 和 outer apply 联接语句 主要用途是:增加 cross apply 和 outer apply 是用于交叉联接表值函数(返回表结果集的函数)的, 更重要的是这个函数的参数是另一个...
  • 通过apply进行数据预处理

    千次阅读 2020-08-12 19:36:54
    通过apply进行数据预处理通过apply进行数据预处理引入相关库数据获取数据分割处理数据删除处理 通过apply进行数据预处理 引入相关库 import numpy as np import pandas as pd from pandas import Series,DataFrame ...
  • pandas apply加速

    2020-06-07 02:48:25
    使用map速度比apply快 def func(S1, S2): #do something return #data['similarity'] =pd.Series() data['similarity'] = list(map(func,data['col1'], data['col2'])) #data['similarity'] = data.apply(lambda...
  • cross apply 和 outer apply

    千次阅读 2010-12-29 11:21:00
    使用APPLY运算符可以实现查询操作的外部表表达式返回的每个调用表值函数。表值函数作为右输入,外部表表达式作为左输入。 通过对右输入求值来获得左输入每一行的计算结果,生成的行被组合起来作为最终输出。APPLY...
  • Python中的lambda和apply用法

    万次阅读 多人点赞 2018-09-03 12:38:10
    Apply 2.1 举例 2.2 下面的例子是DataFrame中apply的用法 3 参考文献 1 lambda lambda原型为:lambda 参数:操作(参数) lambda函数也叫匿名函数,即没有具体名称的函数,它允许快速定义单行函数,可以用在...
  • apply函数 对矩阵、数据框、数组(二维、多维)等矩阵型数据,按行或列应用函数FUN进行循环计算,并以返回计算结果 apply(X, MARGIN, FUN, ...) X:数组、矩阵、数据框等矩阵型数据 MARGIN: 按行计算或按按列计算,1...
  • outer apply 与 cross apply

    千次阅读 2010-09-21 20:19:00
    cross apply 和 outer apply 对于 table1 中的每一行都和派生表(表值函数根据table1当前行数据生成的动态结果集) 做了一个交叉联接。cross apply 和 outer apply 的区别在于: 如果根据table1的某行数据...
  • 首先扯点历史(链接): 在python的幼儿时期,执行带参数的function是这样的: apply(function, args, kwargs) apply在python2.7里还有,当然python3.x没有了,现在直接 ...然后再说applyapply_...
  • call apply bind

    千次阅读 2018-11-12 10:12:37
    JavaScript的call,apply和bind的区别 相同点是三者都可以把一个函数应用到其他对象上;都是用来改变函数的this对象的指向的;第一个参数都是this要指向的对象;都可以利用后续参数传参。不同点是call,apply是修改...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,235
精华内容 55,694
关键字:

apply