精华内容
参与话题
问答
  • C语言 sizeof操作符详解

    万次阅读 多人点赞 2012-02-09 21:33:59
    sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“ 辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能详细的总结一下。 但当我总结的时候才发现,这个问题既可以简单,又可以复杂...

    sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“
    辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能详细的总结一下。
    但当我总结的时候才发现,这个问题既可以简单,又可以复杂,所以本文有的地方并不
    适合初学者,甚至都没有必要大作文章。但如果你想“知其然,更知其所以然”的话,
    那么这篇文章对你或许有所帮助。
    菜鸟我对C++的掌握尚未深入,其中不乏错误,欢迎各位指正啊

    1. 定义:
    sizeof是何方神圣sizeof乃C/C++中的一个操作符(operator)是也,简单的说其作
    用就是返回一个对象或者类型所占的内存字节数。
    MSDN上的解释为:
    The sizeof keyword gives the amount of storage, in bytes, associated with a
    variable or a type (including aggregate types).
    This keyword returns a value of type size_t.
    其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一
    般定义为
    typedef unsigned int size_t;
    世上编译器林林总总,但作为一个规范,它们都会保证char、signed char和unsigned
    char的sizeof值为1,毕竟char是我们编程能用的最小数据类型。
    2. 语法:
    sizeof有三种语法形式,如下:
    1) sizeof( object ); // sizeof( 对象 );
    2) sizeof( type_name ); // sizeof( 类型 );
    3) sizeof object; // sizeof 对象;
    所以,
    int i;
    sizeof( i ); // ok
    sizeof i; // ok
    sizeof( int ); // ok
    sizeof int; // error
    既然写法3可以用写法1代替,为求形式统一以及减少我们大脑的负担,第3种写法,忘
    掉它吧!
    实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的
    不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以
    对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式
    进行计算。如:
    sizeof( 2 );// 2的类型为int,所以等价于 sizeof( int );
    sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价
    于 sizeof( double );
    sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用
    ,我们来看一个完整的例子:
    char foo()
    {
    printf("foo() has been called./n");
    return 'a';
    }
    int main()
    {
    size_t sz = sizeof( foo() ); // foo() 的返回值类型为char,所以sz = sizeof(
    char ),foo()并不会被调用
    printf("sizeof( foo() ) = %d/n", sz);
    }
    C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算s
    izeof值,即下面这些写法都是错误的:
    sizeof( foo );// error
    void foo2() { }
    sizeof( foo2() );// error
    struct S
    {
    unsigned int f1 : 1;
    unsigned int f2 : 5;
    unsigned int f3 : 12;
    };
    sizeof( S.f1 );// error
    3. sizeof的常量性
    sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
    char ary[ sizeof( int ) * 10 ]; // ok
    最新的C99标准规定sizeof也可以在运行时刻进行计算,如下面的程序在Dev-C++中可以
    正确执行:
    int n;
    n = 10; // n动态赋值
    char ary[n]; // C99也支持数组的动态定义
    printf("%d/n", sizeof(ary)); // ok. 输出10
    但在没有完全实现C99标准的编译器中就行不通了,上面的代码在VC6中就通不过编译。
    所以我们最好还是认为sizeof是在编译期执行的,这样不会带来错误,让程序的可移植
    性强些。
    4. 基本数据类型的sizeof
    这里的基本数据类型指short、int、long、float、double这样的简单内置数据类型,
    由于它们都是和系统相关的,所以在不同的系统下取值可能不同,这务必引起我们的注
    意,尽量不要在这方面给自己程序的移植造成麻烦。
    一般的,在32位编译环境中,sizeof(int)的取值为4。
    5. 指针变量的sizeof
    学过数据结构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既
    然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中
    ,一个指针变量的返回值必定是4(注意结果是以字节为单位),可以预计,在将来的6
    4位系统中指针变量的sizeof结果为8。
    char* pc = "abc";
    int* pi;
    string* ps;
    char** ppc = &pc;
    void (*pf)();// 函数指针
    sizeof( pc ); // 结果为4
    sizeof( pi ); // 结果为4
    sizeof( ps ); // 结果为4
    sizeof( ppc ); // 结果为4
    sizeof( pf );// 结果为4
    指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内
    存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消
    息结构(使用指向结构体的指针)。
    6. 数组的sizeof
    数组的sizeof值等于数组所占用的内存字节数,如:
    char a1[] = "abc";
    int a2[3];
    sizeof( a1 ); // 结果为4,字符 末尾还存在一个NULL终止符
    sizeof( a2 ); // 结果为3*4=12(依赖于int)
    一些朋友刚开始时把sizeof当作了求数组元素的个数,现在,你应该知道这是不对的,
    那么应该怎么求数组元素的个数呢Easy,通常有下面两种写法:
    int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度
    int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度
    写到这里,提一问,下面的c3,c4值应该是多少呢
    void foo3(char a3[3])
    {
    int c3 = sizeof( a3 ); // c3 ==
    }
    void foo4(char a4[])
    {
    int c4 = sizeof( a4 ); // c4 ==
    }
    也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。这里函数参数a3已不
    再是数组类型,而是蜕变成指针,相当于char* a3,为什么仔细想想就不难明白,我
    们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的
    ,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为
    4。
    7. 结构体的sizeof
    这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体

    struct S1
    {
    char c;
    int i;
    };
    问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么
    加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错
    的!VC6中按默认设置得到的结果为8。
    Why为什么受伤的总是我
    请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所
    占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:
    S1 s1 = { 'a', 0xFFFFFFFF };
    定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么
    以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:
    0012FF78: 61 CC CC CC FF FF FF FF
    发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:
    When applied to a structure type or variable, sizeof returns the actual siz
    e, which may include padding bytes inserted for alignment.
    原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。
    为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否
    则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数
    据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,
    让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个
    数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
    让我们交换一下S1中char与int的位置:
    struct S2
    {
    int i;
    char c;
    };
    看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填
    充字节,这又是为什么啊别着急,下面总结规律。

    字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
    1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
    2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,
    如有需要编译器会在成员之间加上填充字节(internal adding);
    3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最
    末一个成员之后加上填充字节(trailing padding)。
    对于上面的准则,有几点需要说明:
    1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有
    了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。

    结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也
    在stddef.h中定义,如下:
    #define offsetof(s,m) (size_t)&(((s *)0)->m)
    例如,想要获得S2中c的偏移量,方法为
    size_t pos = offsetof(S2, c);// pos等于4
    2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型
    ,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型
    ,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子
    成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将
    复合类型作为整体看待。
    这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以
    VC6为例,以后不再说明):
    struct S3
    {
    char c1;
    S1 s;
    char c2
    };
    S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,
    所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整
    除,整个sizeof(S3)的值也应该被4整除。
    c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个
    准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需
    要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补
    上3个填充字节。最后得到sizeof(S3)的值为16。
    通过上面的叙述,我们可以得到一个公式:
    结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:

    sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( tr
    ailing padding )

    到这里,朋友们应该对结构体的sizeof有了一个全新的认识,但不要高兴得太早,有
    一个影响sizeof的重要参量还未被提及,那便是编译器的pack指令。它是用来调整结构
    体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以
    直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐
    数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么
    该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,
    公式如下:
    offsetof( item ) = min( n, sizeof( item ) )
    再看示例:
    #pragma pack(push) // 将当前pack设置压栈保存
    #pragma pack(2)// 必须在结构体定义之前使用
    struct S1
    {
    char c;
    int i;
    };
    struct S3
    {
    char c1;
    S1 s;
    char c2
    };
    #pragma pack(pop) // 恢复先前的pack设置
    计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)
    等于6,能够被2整除,所以整个S1的大小为6。
    同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能
    被2整除,添加一个填充字节,所以sizeof(S3)等于10。
    现在,朋友们可以轻松的出一口气了,:)
    还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不
    占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢于是
    ,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占
    位了。如下:
    struct S5 { };
    sizeof( S5 ); // 结果为1

    8. 含位域结构体的sizeof
    前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构
    体的sizeof,只是考虑到其特殊性而将其专门列了出来。
    C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,
    允许其它类型类型的存在。
    使用位域的主要目的是压缩存储,其大致规则为:
    1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字
    段将紧邻前一个字段存储,直到不能容纳为止;
    2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字
    段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
    3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方
    式,Dev-C++采取压缩方式;
    4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
    5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

    还是让我们来看看例子。
    示例1:
    struct BF1
    {
    char f1 : 3;
    char f2 : 4;
    char f3 : 5;
    };
    其内存布局为:
    |_f1__|__f2__|_|____f3___|____|
    |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
    0 3 7 8 1316
    位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只
    能从下一个字节开始。因此sizeof(BF1)的结果为2。
    示例2:
    struct BF2
    {
    char f1 : 3;
    short f2 : 4;
    char f3 : 5;
    };
    由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。
    示例3:
    struct BF3
    {
    char f1 : 3;
    char f2;
    char f3 : 5;
    };
    非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。
    9. 联合体的sizeof
    结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个
    联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这
    里,复合类型成员是被作为整体考虑的。
    所以,下面例子中,U的sizeof值等于sizeof(s)。
    union U
    {
    int i;
    char c;
    S1 s;
    };

    展开全文
  • 更新数组操作符

    万次阅读 2020-06-20 01:39:43
    操作符 作用 $addToSet 向数组中添加元素 $pop 从数组中移除元素 $pull 从数组中有选择性地移除元素 $pullAll 从数组中有选择性的一次元素 $push 向数组中添加元素 { $addToSet:{name:value} } #原来...
    操作符 作用
    $addToSet 向数组中添加元素
    $pop 从数组中移除元素
    $pull 从数组中有选择性地移除元素
    $pullAll 从数组中有选择性的一次元素
    $push 向数组中添加元素
    { $addToSet:{name:value} }  #原来就有则不会添加
    { $pop:{name:value} }  #删除内嵌数组中元素value=1删除最后一个,-1是删除第一个元素
    { $pull:{name:value} }  #原来就有则不会添加
    { $pullAll:{name:value} }  #原来就有则不会添加
    { $push:{name:value} }  #原来就有则不会添加
    
    展开全文
  • 定义了一个成员操作符,并且有三个非成员操作符。这些非成员操作符需要访问 私有数据成员,声明为友元: ``` class Sales_item { friend std::istream& operator>> (std::istream&, Sales_item&); friend ...
  • Android RxJava操作符详解系列: 变换操作符

    万次阅读 多人点赞 2017-10-23 09:24:11
    前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章:...今天,我将为大家详细介绍RxJava操作符中最常用的变换操作符,并附带 Ret

    前言

    • Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。

    Github截图

    如果还不了解 RxJava,请看文章:Android:这是一篇 清晰 & 易懂的Rxjava 入门教程

    • RxJava如此受欢迎的原因,在于其提供了丰富 & 功能强大的操作符,几乎能完成所有的功能需求
    • 今天,我将为大家详细介绍RxJava操作符中最常用的变换操作符,并附带 Retrofit 结合 RxJava的实例Demo教学,希望你们会喜欢。
    1. 本系列文章主要基于 Rxjava 2.0
    2. 接下来的时间,我将持续推出 AndroidRxjava 2.0 的一系列文章,包括原理、操作符、应用场景、背压等等 ,有兴趣可以继续关注Carson_Ho的安卓开发笔记!!

    示意图


    目录

    示意图


    1. 作用

    • 对事件序列中的事件 / 整个事件序列 进行加工处理(即变换),使得其转变成不同的事件 / 整个事件序列
    • 具体原理如下

    示意图


    2. 类型

    • RxJava中常见的变换操作符如下:
      示意图

    • 下面,我将对每种操作符进行详细介绍

    注:本文只讲解RxJava2在开发过程中常用的变换操作符


    3. 应用场景 & 对应操作符 介绍

    • 下面,我将对 RxJava2 中的变换操作符进行逐个讲解
    • 注:在使用RxJava 2操作符前,记得在项目的Gradle中添加依赖:
    dependencies {
          compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
          compile 'io.reactivex.rxjava2:rxjava:2.0.7'
          // 注:RxJava2 与 RxJava1 不能共存,即依赖不能同时存在
    }
    

    3.1 Map()

    • 作用
      对 被观察者发送的每1个事件都通过 指定的函数 处理,从而变换成另外一种事件

    即, 将被观察者发送的事件转换为任意的类型事件。

    • 原理

    示意图

    • 应用场景
      数据类型转换

    • 具体使用
      下面以将 使用Map() 将事件的参数从 整型 变换成 字符串类型 为例子说明

    示意图

     // 采用RxJava基于事件流的链式操作
            Observable.create(new ObservableOnSubscribe<Integer>() {
    
                // 1. 被观察者发送事件 = 参数为整型 = 1、2、3
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    emitter.onNext(1);
                    emitter.onNext(2);
                    emitter.onNext(3);
    
                }
                // 2. 使用Map变换操作符中的Function函数对被观察者发送的事件进行统一变换:整型变换成字符串类型
            }).map(new Function<Integer, String>() {
                @Override
                public String apply(Integer integer) throws Exception {
                    return "使用 Map变换操作符 将事件" + integer +"的参数从 整型"+integer + " 变换成 字符串类型" + integer ;
                }
            }).subscribe(new Consumer<String>() {
    
                // 3. 观察者接收事件时,是接收到变换后的事件 = 字符串类型
                @Override
                public void accept(String s) throws Exception {
                    Log.d(TAG, s);
                }
            });
    
    
    • 测试结果

    示意图

    从上面可以看出,map() 将参数中的 Integer 类型对象转换成一个 String类型 对象后返回

    同时,事件的参数类型也由 Integer 类型变成了 String 类型


    3.2 FlatMap()

    • 作用:将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送

    • 原理

    1. 为事件序列中每个事件都创建一个 Observable 对象;
    2. 将对每个 原始事件 转换后的 新事件 都放入到对应 Observable对象;
    3. 将新建的每个Observable 都合并到一个 新建的、总的Observable 对象;
    4. 新建的、总的Observable 对象 将 新合并的事件序列 发送给观察者(Observer

    示意图

    • 应用场景
      无序的将被观察者发送的整个事件序列进行变换

    • 具体使用

    // 采用RxJava基于事件流的链式操作
            Observable.create(new ObservableOnSubscribe<Integer>() {
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    emitter.onNext(1);
                    emitter.onNext(2);
                    emitter.onNext(3);
                }
    
                // 采用flatMap()变换操作符
            }).flatMap(new Function<Integer, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(Integer integer) throws Exception {
                    final List<String> list = new ArrayList<>();
                    for (int i = 0; i < 3; i++) {
                        list.add("我是事件 " + integer + "拆分后的子事件" + i);
                        // 通过flatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
                        // 最终合并,再发送给被观察者
                    }
                    return Observable.fromIterable(list);
                }
            }).subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.d(TAG, s);
                }
            });
    
    • 测试结果
      示意图

    注:新合并生成的事件序列顺序是无序的,即 与旧序列发送事件的顺序无关

    3.3 ConcatMap()

    • 作用:类似FlatMap()操作符

    • FlatMap()的 区别在于:拆分 & 重新合并生成的事件序列 的顺序 = 被观察者旧序列生产的顺序

    • 原理

    示意图

    • 应用场景
      有序的将被观察者发送的整个事件序列进行变换

    • 具体使用

    // 采用RxJava基于事件流的链式操作
            Observable.create(new ObservableOnSubscribe<Integer>() {
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    emitter.onNext(1);
                    emitter.onNext(2);
                    emitter.onNext(3);
                }
    
                // 采用concatMap()变换操作符
            }).concatMap(new Function<Integer, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(Integer integer) throws Exception {
                    final List<String> list = new ArrayList<>();
                    for (int i = 0; i < 3; i++) {
                        list.add("我是事件 " + integer + "拆分后的子事件" + i);
                        // 通过concatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
                        // 最终合并,再发送给被观察者
                    }
                    return Observable.fromIterable(list);
                }
            }).subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.d(TAG, s);
                }
            });
    
    • 测试结果
      示意图

    注:新合并生成的事件序列顺序是有序的,即 严格按照旧序列发送事件的顺序


    3.4 Buffer()

    • 作用
      定期从 被观察者(Obervable)需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送

    • 原理

    示意图

    • 应用场景
      缓存被观察者发送的事件

    • 具体使用
      那么,Buffer()每次是获取多少个事件放到缓存区中的呢?下面我将通过一个例子来说明

    // 被观察者 需要发送5个数字
            Observable.just(1, 2, 3, 4, 5)
                    .buffer(3, 1) // 设置缓存区大小 & 步长
                                        // 缓存区大小 = 每次从被观察者中获取的事件数量
                                        // 步长 = 每次获取新事件的数量
                    .subscribe(new Observer<List<Integer>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
    
                        }
                        @Override
                        public void onNext(List<Integer> stringList) {
                            //
                            Log.d(TAG, " 缓存区里的事件数量 = " +  stringList.size());
                            for (Integer value : stringList) {
                                Log.d(TAG, " 事件 = " + value);
                            }
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应" );
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "对Complete事件作出响应");
                        }
                    });
    
    • 测试结果

    示意图

    • 过程解释

    下面,我将通过一个图来解释Buffer()原理 & 整个例子的结果
    示意图

    至此,关于RxJava2中主要的变换操作符已经讲解完毕


    4. 实际开发需求案例

    • 变换操作符的主要开发需求场景 = 嵌套回调(Callback hell
    • 下面,我将采用一个实际应用场景实例来讲解嵌套回调(Callback hell

    具体请看文章Android RxJava 实际应用案例讲解:网络请求嵌套回调


    5. Demo地址

    上述所有的Demo源代码都存放在:Carson_Ho的Github地址:RxJava2_变换操作符

    喜欢的麻烦点个star


    6. 总结

    • 下面,我将用一张图总结 RxJava2 中常用的变换操作符

    示意图

    • 接下来的时间,我将持续推出 AndroidRxjava 2.0 的一系列文章,包括原理、操作符、应用场景、背压等等

    示意图

    • 感兴趣的同学可以继续关注carson_ho的微信公众号
      示意图
      示意图

    请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

    展开全文
  • Android RxJava操作符详解系列: 创建操作符

    万次阅读 多人点赞 2017-10-16 10:01:59
    前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章:...今天,我将为大家详细介绍RxJava操作符中最常用的创建操作符,并附带 Ret

    前言

    • Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。

    Github截图

    如果还不了解 RxJava,请看文章:Android:这是一篇 清晰 & 易懂的Rxjava 入门教程

    • RxJava如此受欢迎的原因,在于其提供了丰富 & 功能强大的操作符,几乎能完成所有的功能需求
    • 今天,我将为大家详细介绍RxJava操作符中最常用的创建操作符,并附带 Retrofit 结合 RxJava的实例Demo教学,希望你们会喜欢。
    1. 本系列文章主要基于 Rxjava 2.0
    2. 接下来的时间,我将持续推出 AndroidRxjava 2.0 的一系列文章,包括原理、操作符、应用场景、背压等等 ,有兴趣可以继续关注Carson_Ho的安卓开发笔记!!

    示意图


    目录

    示意图


    1. 作用

    创建 被观察者( Observable) 对象 & 发送事件。


    2. 类型

    • 创建操作符包括如下:

    示意图

    • 下面,我将对每个操作符进行详细介绍

    3. 应用场景 & 对应操作符 介绍

    注:在使用RxJava 2操作符前,记得在项目的Gradle中添加依赖:

    dependencies {
          compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
          compile 'io.reactivex.rxjava2:rxjava:2.0.7'
          // 注:RxJava2 与 RxJava1 不能共存,即依赖不能同时存在
    }
    

    3.1 基本创建

    • 需求场景
      完整的创建被观察者对象

    • 对应操作符类型

    create()

    • 作用
      完整创建1个被观察者对象(Observable

    RxJava 中创建被观察者对象最基本的操作符

    • 具体使用
    / **
       * 1. 通过creat()创建被观察者 Observable 对象
       */ 
            Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
              // 传入参数: OnSubscribe 对象
              // 当 Observable 被订阅时,OnSubscribe 的 call() 方法会自动被调用,即事件序列就会依照设定依次被触发
              // 即观察者会依次调用对应事件的复写方法从而响应事件
              // 从而实现由被观察者向观察者的事件传递 & 被观察者调用了观察者的回调方法 ,即观察者模式
    / **
       * 2. 在复写的subscribe()里定义需要发送的事件
       */ 
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                    // 通过 ObservableEmitter类对象 产生 & 发送事件
                    // ObservableEmitter类介绍
                        // a. 定义:事件发射器
                        // b. 作用:定义需要发送的事件 & 向观察者发送事件
                       // 注:建议发送事件前检查观察者的isUnsubscribed状态,以便在没有观察者时,让Observable停止发射数据
                        if (!observer.isUnsubscribed()) {
                               emitter.onNext(1);
                               emitter.onNext(2);
                               emitter.onNext(3);
                    }
                    emitter.onComplete();
                }
            });
    
    // 至此,一个完整的被观察者对象(Observable)就创建完毕了。
    
    
    

    在具体使用时,一般采用 链式调用 来创建

            // 1. 通过creat()创建被观察者对象
            Observable.create(new ObservableOnSubscribe<Integer>() {
    
                // 2. 在复写的subscribe()里定义需要发送的事件
                @Override
                public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
    
                        emitter.onNext(1);
                        emitter.onNext(2);
                        emitter.onNext(3);
    
                    emitter.onComplete();
                }  // 至此,一个被观察者对象(Observable)就创建完毕
            }).subscribe(new Observer<Integer>() {
                // 以下步骤仅为展示一个完整demo,可以忽略
                // 3. 通过通过订阅(subscribe)连接观察者和被观察者
                // 4. 创建观察者 & 定义响应事件的行为
                @Override
                public void onSubscribe(Disposable d) {
                    Log.d(TAG, "开始采用subscribe连接");
                }
                // 默认最先调用复写的 onSubscribe()
    
                @Override
                public void onNext(Integer value) {
                    Log.d(TAG, "接收到了事件"+ value  );
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "对Error事件作出响应");
                }
    
                @Override
                public void onComplete() {
                    Log.d(TAG, "对Complete事件作出响应");
                }
    
            });
        }
    
    
    • 测试结果

    示意图

    3.2 快速创建 & 发送事件

    • 需求场景
      快速的创建被观察者对象

    • 对应操作符类型

    just()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:直接发送 传入的事件

    注:最多只能发送10个参数

    • 应用场景
      快速创建 被观察者对象(Observable) & 发送10个以下事件

    • 具体使用

            // 1. 创建时传入整型1、2、3、4
            // 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
            Observable.just(1, 2, 3,4)   
                // 至此,一个Observable对象创建完毕,以下步骤仅为展示一个完整demo,可以忽略
                // 2. 通过通过订阅(subscribe)连接观察者和被观察者
                // 3. 创建观察者 & 定义响应事件的行为
             .subscribe(new Observer<Integer>() {
                
                @Override
                public void onSubscribe(Disposable d) {
                    Log.d(TAG, "开始采用subscribe连接");
                }
                // 默认最先调用复写的 onSubscribe()
    
                @Override
                public void onNext(Integer value) {
                    Log.d(TAG, "接收到了事件"+ value  );
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "对Error事件作出响应");
                }
    
                @Override
                public void onComplete() {
                    Log.d(TAG, "对Complete事件作出响应");
                }
    
            });
        }
    
    • 测试结果

    示意图

    fromArray()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:直接发送 传入的数组数据

    会将数组中的数据转换为Observable对象

    • 应用场景

      1. 快速创建 被观察者对象(Observable) & 发送10个以上事件(数组形式)
      2. 数组元素遍历
    • 具体使用

          // 1. 设置需要传入的数组
         Integer[] items = { 0, 1, 2, 3, 4 };
    
            // 2. 创建被观察者对象(Observable)时传入数组
            // 在创建后就会将该数组转换成Observable & 发送该对象中的所有数据
            Observable.fromArray(items) 
            .subscribe(new Observer<Integer>() {
                @Override
                public void onSubscribe(Disposable d) {
                    Log.d(TAG, "开始采用subscribe连接");
                }
    
                @Override
                public void onNext(Integer value) {
                    Log.d(TAG, "接收到了事件"+ value  );
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "对Error事件作出响应");
                }
    
                @Override
                public void onComplete() {
                    Log.d(TAG, "对Complete事件作出响应");
                }
    
            });
        }
    
    // 注:
    // 可发送10个以上参数
    // 若直接传递一个list集合进去,否则会直接把list当做一个数据元素发送
    
    /*
      * 数组遍历
      **/
            // 1. 设置需要传入的数组
            Integer[] items = { 0, 1, 2, 3, 4 };
    
            // 2. 创建被观察者对象(Observable)时传入数组
            // 在创建后就会将该数组转换成Observable & 发送该对象中的所有数据
            Observable.fromArray(items)
                    .subscribe(new Observer<Integer>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "数组遍历");
                        }
    
                        @Override
                        public void onNext(Integer value) {
                            Log.d(TAG, "数组中的元素 = "+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "遍历结束");
                        }
    
                    });
    
    
    • 测试结果

    发送事件

    数组遍历

    fromIterable()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:直接发送 传入的集合List数据

    会将数组中的数据转换为Observable对象

    • 应用场景

      1. 快速创建 被观察者对象(Observable) & 发送10个以上事件(集合形式)
      2. 集合元素遍历
    • 具体使用

    /*
     * 快速发送集合
     **/
    // 1. 设置一个集合
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
    // 2. 通过fromIterable()将集合中的对象 / 数据发送出去
            Observable.fromIterable(list)
                    .subscribe(new Observer<Integer>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "开始采用subscribe连接");
                        }
    
                        @Override
                        public void onNext(Integer value) {
                            Log.d(TAG, "接收到了事件"+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "对Complete事件作出响应");
                        }
                    });
    
    
    /*
     * 集合遍历
     **/
            // 1. 设置一个集合
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            // 2. 通过fromIterable()将集合中的对象 / 数据发送出去
            Observable.fromIterable(list)
                    .subscribe(new Observer<Integer>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "集合遍历");
                        }
    
                        @Override
                        public void onNext(Integer value) {
                            Log.d(TAG, "集合中的数据元素 = "+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "遍历结束");
                        }
                    });
    
    • 测试结果

    发送集合

    集合遍历

    额外

    // 下列方法一般用于测试使用
    
    <-- empty()  -->
    // 该方法创建的被观察者对象发送事件的特点:仅发送Complete事件,直接通知完成
    Observable observable1=Observable.empty(); 
    // 即观察者接收后会直接调用onCompleted()
    
    <-- error()  -->
    // 该方法创建的被观察者对象发送事件的特点:仅发送Error事件,直接通知异常
    // 可自定义异常
    Observable observable2=Observable.error(new RuntimeException())
    // 即观察者接收后会直接调用onError()
    
    <-- never()  -->
    // 该方法创建的被观察者对象发送事件的特点:不发送任何事件
    Observable observable3=Observable.never();
    // 即观察者接收后什么都不调用
    
    

    3.3 延迟创建

    • 需求场景
      1. 定时操作:在经过了x秒后,需要自动执行y操作
      2. 周期性操作:每隔x秒后,需要自动执行y操作

    defer()

    • 作用
      直到有观察者(Observer )订阅时,才动态创建被观察者对象(Observable) & 发送事件
    1. 通过 Observable工厂方法创建被观察者对象(Observable
    2. 每次订阅后,都会得到一个刚创建的最新的Observable对象,这可以确保Observable对象里的数据是最新的
    • 应用场景
      动态创建被观察者对象(Observable) & 获取最新的Observable对象数据

    • 具体使用

           <-- 1. 第1次对i赋值 ->>
            Integer i = 10;
    
            // 2. 通过defer 定义被观察者对象
            // 注:此时被观察者对象还没创建
            Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
                @Override
                public ObservableSource<? extends Integer> call() throws Exception {
                    return Observable.just(i);
                }
            });
    
            <-- 2. 第2次对i赋值 ->>
            i = 15;
    
            <-- 3. 观察者开始订阅 ->>
            // 注:此时,才会调用defer()创建被观察者对象(Observable)
            observable.subscribe(new Observer<Integer>() {
    
                @Override
                public void onSubscribe(Disposable d) {
                    Log.d(TAG, "开始采用subscribe连接");
                }
    
                @Override
                public void onNext(Integer value) {
                    Log.d(TAG, "接收到的整数是"+ value  );
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "对Error事件作出响应");
                }
    
                @Override
                public void onComplete() {
                    Log.d(TAG, "对Complete事件作出响应");
                }
            });
    
    • 测试结果

    因为是在订阅时才创建,所以i值会取第2次的赋值
    示意图

    timer()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:延迟指定时间后,发送1个数值0(Long类型)

    本质 = 延迟指定时间后,调用一次 onNext(0)

    • 应用场景
      延迟指定事件,发送一个0,一般用于检测

    • 具体使用

            // 该例子 = 延迟2s后,发送一个long类型数值
            Observable.timer(2, TimeUnit.SECONDS) 
                      .subscribe(new Observer<Long>() {
                @Override
                public void onSubscribe(Disposable d) {
                    Log.d(TAG, "开始采用subscribe连接");
                }
    
                @Override
                public void onNext(Long value) {
                    Log.d(TAG, "接收到了事件"+ value  );
                }
    
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "对Error事件作出响应");
                }
    
                @Override
                public void onComplete() {
                    Log.d(TAG, "对Complete事件作出响应");
                }
    
            });
    
    // 注:timer操作符默认运行在一个新线程上
    // 也可自定义线程调度器(第3个参数):timer(long,TimeUnit,Scheduler) 
    
    • 测试结果

    示意图

    interval()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:每隔指定时间 就发送 事件

    发送的事件序列 = 从0开始、无限递增1的的整数序列

    • 具体使用
           // 参数说明:
            // 参数1 = 第1次延迟时间;
            // 参数2 = 间隔时间数字;
            // 参数3 = 时间单位;
            Observable.interval(3,1,TimeUnit.SECONDS)
                    // 该例子发送的事件序列特点:延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
                    .subscribe(new Observer<Long>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "开始采用subscribe连接");
                        }
                        // 默认最先调用复写的 onSubscribe()
    
                        @Override
                        public void onNext(Long value) {
                            Log.d(TAG, "接收到了事件"+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "对Complete事件作出响应");
                        }
    
                    });
    
    // 注:interval默认在computation调度器上执行
    // 也可自定义指定线程调度器(第3个参数):interval(long,TimeUnit,Scheduler)
    
    • 测试结果

    示意图

    intervalRange()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:每隔指定时间 就发送 事件,可指定发送的数据的数量

    a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
    b. 作用类似于interval(),但可指定发送的数据的数量

    • 具体使用
    // 参数说明:
            // 参数1 = 事件序列起始点;
            // 参数2 = 事件数量;
            // 参数3 = 第1次事件延迟发送时间;
            // 参数4 = 间隔时间数字;
            // 参数5 = 时间单位
            Observable.intervalRange(3,10,2, 1, TimeUnit.SECONDS)
                    // 该例子发送的事件序列特点:
                    // 1. 从3开始,一共发送10个事件;
                    // 2. 第1次延迟2s发送,之后每隔2秒产生1个数字(从0开始递增1,无限个)
                    .subscribe(new Observer<Long>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "开始采用subscribe连接");
                        }
                        // 默认最先调用复写的 onSubscribe()
    
                        @Override
                        public void onNext(Long value) {
                            Log.d(TAG, "接收到了事件"+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "对Complete事件作出响应");
                        }
    
                    });
    
    • 测试结果

    示意图

    range()

    • 作用
      1. 快速创建1个被观察者对象(Observable
      2. 发送事件的特点:连续发送 1个事件序列,可指定范围

    a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
    b. 作用类似于intervalRange(),但区别在于:无延迟发送事件

    • 具体使用
    
    // 参数说明:
            // 参数1 = 事件序列起始点;
            // 参数2 = 事件数量;
            // 注:若设置为负数,则会抛出异常
            Observable.range(3,10)
                    // 该例子发送的事件序列特点:从3开始发送,每次发送事件递增1,一共发送10个事件
                    .subscribe(new Observer<Integer>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            Log.d(TAG, "开始采用subscribe连接");
                        }
                        // 默认最先调用复写的 onSubscribe()
    
                        @Override
                        public void onNext(Integer value) {
                            Log.d(TAG, "接收到了事件"+ value  );
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.d(TAG, "对Error事件作出响应");
                        }
    
                        @Override
                        public void onComplete() {
                            Log.d(TAG, "对Complete事件作出响应");
                        }
    
                    });
    
    
    • 测试结果

    示意图

    rangeLong()

    • 作用:类似于range(),区别在于该方法支持数据类型 = Long
    • 具体使用
      range()类似,此处不作过多描述

    至此,关于 RxJava2中的创建操作符讲解完毕。


    4. 实际开发需求案例

    • 下面,我将讲解创建操作符的1个常见实际需求案例:网络请求轮询
    • 该例子将结合RetrofitRxJava 进行讲解

    具体请看文章:Android RxJava 实际应用案例讲解:网络请求轮询


    5. Demo地址

    上述所有的Demo源代码都存放在:Carson_Ho的Github地址:RxJava2_创建操作符


    6. 总结

    • 下面,我将用1张图总结 RxJava2 中常用的创建操作符

    示意图

    • 接下来的时间,我将持续推出 AndroidRxjava 2.0 的一系列文章,包括原理、操作符、应用场景、背压等等
      示意图
    • 感兴趣的同学可以继续关注carson_ho的微信公众号
      示意图
      示意图

    请 帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

    展开全文
  • C++的重载操作符(operator)介绍

    万次阅读 多人点赞 2018-06-11 16:40:12
    本文主要介绍C++中的重载操作符(operator)的相关知识。 1. 概述 1.1 what operator 是C++的一个关键字,它和运算符(如=)一起使用,表示一个运算符重载函数,在理解时可将operator和运算符(如operator=)...
  • 前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章...今天,我将为大家详细介绍RxJava操作符中最常用的 过滤操作符,希望你们会喜
  • 前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章:...今天,我将为大家详细介绍RxJava操作符中最常用的 组合 / 合并操作符,并
  • 前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章:...今天,我将为大家详细介绍RxJava操作符中最常用的 功能性操作符,并附带 R
  • 1.二元和三元操作符 操作符始终写在前一行,以免分号的隐式插入产生预想不到的问题 var x=a?b:c; var y=a? longExpressionA:longExpressionB; var z=a? longExpressionC: longExpressionD; 2.&amp;&...
  • 前言 Rxjava,由于其基于事件流的链式调用、逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎。 如果还不了解 RxJava,请看文章:...今天,我将为大家详细介绍RxJava操作符中最常用的 条件 / 布尔操作符,希
  • RxJava(10-操作符原理&自定义操作符)

    千次阅读 2016-06-30 15:59:11
    转载请标明出处: ...本文出自:【openXu的博客】目录:自定义创建操作符 数据序列操作符lift ...源码下载  通过前面一系列操作符的学习,我们基本上了解了RxJava中的操作符,并大概知道他们有什么作用。
  • 移位操作符

    千次阅读 2014-07-20 01:08:58
    移位操作符操作的运算对象也是 二进制的
  • 你可以实现你自己的Observable操作符,本文展示怎么做。如果你的操作符是被用于创造一个Observable,而不是变换或者响应一个Observable,使用 create( ) 方法,不要试图手动实现 Observable。另外,你可以按照下面...
  • 这个场景单片机开发中经常使用,方法就是先对需要设置的位用&操作符进行清零操作, 然后用|操作符设值。比如我要改变 GPIOA 的状态,可以先对寄存器的值进行&清零操作 GPIOA->CRL&=0XFFFFFF0F; //将第 4-7 位清 0 ...
  • 1,Verilog逻辑操作符 逻辑操作符 功能 A与B的运算 C与D的运算 &amp;&amp; 逻辑与 A&amp;&amp;B= 0 C&amp;...
  • RxJava(三) flatMap 操作符用法详解

    万次阅读 2016-05-29 16:55:03
    一、RxJava create操作符的用法和源码分析 二、RxJava map操作符用法详解 三、RxJava flatMap操作符用法详解 四、RxJava concatMap操作符用法详解 五、RxJava onErrorResumeNext操作符实现app与服务器间...
  • Delaydelay的意思就是延迟,这个操作符会延迟一段指定的时间再发射Observable的数据。 RxJava的实现是 delay和delaySubscription。delay:让原始Observable在发射每项数据之前都暂停一段指定的时间段,结果是...
  • 移位操作符和位操作符

    千次阅读 2019-05-22 21:55:59
    移位操作符   在了解移位操作符和位操作符之前,我们需要知道一个十进制的整数是如何在计算机中存储的,以int a = 10 为例,int型占4个字节,一个字节有8位,正数十以二进制存储在这32位中,其在内存中的存储如下...
  • 构串操作符#和合并操作符##的用法

    千次阅读 2013-05-14 20:07:12
    构串操作符#: #include using namespace std; #define P(x) cout ; #define Q(x) cout ; #define R(x) cout ; int main() { P(CPlusPlus); Q(v
  • 操作符和箭头操作符

    千次阅读 2011-04-16 08:59:00
    C++语言为包含点操作符和解引用操作符的表达式提供了一个同义词:箭头操作符(->)。点操作符用于获取类类型对象的成员:item1.same_isbn(item2); // run the same_isbn member of item1如果有一个指向Sales_item...
  • 关系操作符和逻辑操作符

    千次阅读 2007-08-07 14:42:00
    ! 逻辑非 !expr > 大于 expr > expr >= 大于等于 ...= expr && 逻辑与 expr && expr || 逻辑或 expr || expr 关系操作符和逻辑操作符使用算术或指针类型的操作数,并返回bool类型的值.1.逻辑与、逻辑或操作符
  • Rest参数与Spread操作符

    万次阅读 2019-05-11 15:07:11
    Rest参数(剩余参数)…: 在 JavaScript 中,很多内建函数都支持传入任意个参数。 例如: Math.max(arg1, arg2, …, argN) —— 返回入参中的最大值。 Object.assign(dest, src1, …, srcN) —— 依次合并 src1…N...
  • Java 语言的比较操作符和逻辑操作符,这些操作符的运算结果都是boolean 型。 “”、“=” 操作符的操作元只能是整数类型和浮点数类型。“==”、“!=” 操作符的操作元既可以是基本类型,也可以是引用类型。 “&&”...
  • AllAll操作符根据一个函数对源Observable发射的所有数据进行判断,最终返回的结果就是这个判断结果。这个函数使用发射的数据作为参数,内部判断所有的数据是否满足我们定义好的判断条件,如果全部都满足则返回true,...
  • RxJava 操作符map

    千次阅读 2016-05-24 21:33:32
    map名词是地图的意思,那么这样理解这个操作符就很想不通这个操作符的 应用场景了,但我们敲代码的不可能不熟悉这一个数据结构.在我使用这个操作符的理解中,map就是变换需要操作的数据内容或者结构的意思。所以其...
  • RxJava concatMap操作符

    千次阅读 2016-06-20 14:57:45
    concatMap 作用concatMap操作符和flatMap操作符非常类似。下面是concatMap操作符的流程图:concatMap和flatMap最大的区别是concatMap发射的数据集是有序的,flatMap发射的数据集是无序的。如下代码:Observable.from...
  • RxJava连接操作符

    千次阅读 2016-11-27 18:28:47
    RxJava连接操作符目录RxJava连接操作符目录 Publish 示例代码 Connect 示例代码 RefCount 示例代码ConnectableObservable 和它的子类以及它们的操作符: ConnectableObservable.connect() — 指示一个可连接的...
  • js 移位操作符

    万次阅读 2014-04-17 09:34:08
    1、左移运算    左移运算由两个小于号表示(。它把数字钟的所有数位向左移动指定的数量。例如,把数字2左移5位没结果为64(等于二进制中的1000000)。... 注意,在左移数位时,数字右边多出5个
  • kotlin集合操作符——过滤操作符

    千次阅读 2017-09-22 17:47:11
    关于集合的操作符,直接引用书上的内容,基本上总结的很好了。 val list = listOf(1, 2, 3, 4, 5, 6) drop 返回包含去掉前n个元素的所有元素的列表。 assertEquals(lis

空空如也

1 2 3 4 5 ... 20
收藏数 114,206
精华内容 45,682
关键字:

操作符