• [技术干货] 函数式、并发式、过程式、面向对象风格的编程范式
    编程范式(Programming Paradigm)是编程的“风格”或“方法论”,它定义了程序员如何组织代码、管理数据和控制流程。以下是 函数式、并发式、过程式和面向对象 四种常见编程范式的核心概念和示例:1. 函数式编程(Functional Programming, FP)核心思想函数是一等公民:函数可以像变量一样传递、返回或存储。避免副作用:函数不修改外部状态,仅依赖输入参数并返回输出。不可变数据:数据一旦创建就不能修改,避免意外变更。高阶函数:函数可以接受其他函数作为参数,或返回函数。示例(Python)# 高阶函数:map 遍历列表并应用函数 numbers = [1, 2, 3, 4] squared = list(map(lambda x: x ** 2, numbers)) # [1, 4, 9, 16] # 纯函数:无副作用,输入相同则输出相同 def add(a, b): return a + b # 不修改外部变量 # 递归代替循环(避免可变状态) def factorial(n): return 1 if n == 0 else n * factorial(n - 1) 适用场景数据处理(如 MapReduce、大数据分析)。并行计算(无副作用的函数易并行化)。函数组合(如前端 React 的 useState 钩子)。2. 并发式编程(Concurrent Programming)核心思想同时执行多个任务:通过多线程、多进程或异步 I/O 实现。共享资源管理:避免竞态条件(Race Condition)和数据竞争。同步机制:使用锁、信号量、通道(Channel)等协调任务。示例(Python 多线程)import threading # 共享资源 counter = 0 lock = threading.Lock() def increment(): global counter with lock: # 加锁避免竞态条件 counter += 1 threads = [] for _ in range(100): t = threading.Thread(target=increment) threads.append(t) t.start() for t in threads: t.join() print(counter) # 输出 100(无锁时可能小于 100) 其他并发模型异步编程(Async/Await):如 JavaScript 的 Promise 或 Python 的 asyncio。Actor 模型:如 Erlang/Elixir 的进程间通信。CSP(Communicating Sequential Processes):如 Go 的 goroutine 和 channel。适用场景高并发服务器(如 Web 后端、聊天应用)。I/O 密集型任务(如爬虫、文件处理)。实时系统(如游戏、金融交易)。3. 过程式编程(Procedural Programming)核心思想步骤化:将程序分解为一系列过程(函数)和语句。顺序执行:代码从上到下执行,通过函数调用组织逻辑。全局数据:变量可以全局访问(需谨慎管理)。示例(C 语言)#include <stdio.h> // 全局变量 int global_var = 10; // 过程(函数) void print_sum(int a, int b) { int result = a + b + global_var; printf("Sum: %d\n", result); } int main() { int x = 5, y = 3; print_sum(x, y); // 调用过程 return 0; } 特点自顶向下设计:先写主流程,再拆分函数。易理解:适合小型程序或脚本。缺点:数据与逻辑分离,大型项目易混乱。适用场景简单脚本(如 Bash、Python 脚本)。嵌入式系统(资源受限时)。教学(初学者易上手)。4. 面向对象编程(Object-Oriented Programming, OOP)核心思想对象:数据(属性)和操作(方法)的封装体。类:对象的模板,定义属性和方法。四大特性:封装:隐藏内部细节,暴露接口。继承:子类复用父类代码。多态:同一方法在不同类中有不同实现。抽象:提取关键特征,忽略非本质细节。示例(Python)# 类定义 class Animal: def __init__(self, name): self.name = name # 属性 def speak(self): # 方法 raise NotImplementedError("子类必须实现此方法") # 继承 class Dog(Animal): def speak(self): return f"{self.name} 说:汪汪!" class Cat(Animal): def speak(self): return f"{self.name} 说:喵喵!" # 多态 animals = [Dog("阿黄"), Cat("小花")] for animal in animals: print(animal.speak()) # 输出: # 阿黄 说:汪汪! # 小花 说:喵喵! 适用场景大型软件(如 GUI 应用、游戏引擎)。需要建模现实世界的系统(如银行账户、电商订单)。代码复用(通过继承和多态)。总结对比范式核心单位状态管理典型语言适用场景函数式函数不可变Haskell, Erlang数据处理、并行计算并发式任务/协程共享资源同步Go, Elixir高并发、实时系统过程式过程/函数全局变量C, Pascal简单脚本、嵌入式系统面向对象对象/类封装属性Java, Python大型软件、建模现实世界混合使用现代语言通常支持多种范式(如 Python 支持函数式、过程式和 OOP):# Python 混合范式示例 from functools import reduce # 函数式 numbers = [1, 2, 3] sum_func = reduce(lambda x, y: x + y, numbers) # 6 # 面向对象 class Calculator: def add(self, a, b): return a + b calc = Calculator() sum_oop = calc.add(1, 2) # 3 选择范式时,需根据 问题域(如数据处理用函数式,GUI 用 OOP)和 团队习惯 决定。
  • [分享交流] 兰州理工大学举办仓颉语言编程培训
    2025年5月10日在兰州理工大学彭家坪校区求是楼C205举办了一场仓颉语言编程培训,培训由布道师赵宏老师主持,学生布道师惠旭同,学生预备布道师陈康平、孙其翔协助。39名同学参加了培训,同学们在培训方搭建的Jupyter Lab平台上进行了仓颉编程实践,并完成培训测试。后续,培训方将继续组织同学们学习仓颉编程语言,并实践基于仓颉的鸿蒙应用开发。
  • [技术干货] TVM虚拟机
    技术核心优势:1. TVM 引擎支持 Lisp、JavaScript、Python、Ruby、Lua、Pascal、Basic 等多种语法。2. TVM 超微型内核引擎(不足500kb),拥有几百个实用函数。 内核模块非常紧凑,所需系统资源很小,因此与其他语言相比加载执行起来更加快速。3. TVM 建立在通用的UNIX系统的C语言库函数基础上, 可以运行在各种操作系统平台,如Windows,Linux,BSDs,Mac OS等。4. TVM 引擎可以进行源代码链接,生成独立的可执行文件。5. TVM 引擎以共享库库的方式可以嵌入到宿主系统中,可作为应用开发的语言平台。6. 动态脚本语言,简单易学,模块化集成,同时具有教学语言的优点: 透明和友好提示。7. 支持符号单元运算, 任何符号都可以用作定义计算的行为,突破了以往计算机编程汉字仅能作为字符串数据来处理的局面, 可将任何符号(例如:中文、简繁体汉字、少数民族语言文字)作为计算机代码来运行。8. 面向对象,基于原型继承。9. 函数式编程涵盖LISP语言抽象语法、独特的符号、表达式处理等突出特点。10. 同时拥有 C 语言的访问底层数据单元,执行系统操作的灵活快捷的特点,和 C 语言一样可以定义结构,访问结构成员和进行指针操作。11. 动态语言弱类型,数据使用前无需宣告声明。 而C语言在编译的过程中须明确操作数的内存单元大小和长度,因此使用前必须事先申明变量符号和函数符号的数据类型。12. 集中强化符号和表达式的处理和操作。包括修改,插入,删除复杂嵌套列表和多维数组结构中的元素。13. 具有多态函数的特点,参与函数运算的参数类型不限和参数个数不限,这使得定义函数有很强的灵活性。14. 函数是特殊的列表,可以象操作列表一样来对函数进行组合和拆分。 除了定义函数外,还可以用宏实现在重构表达式。15. 支持流的输入输出操作,可以包含控制字符的二进制数据访问。16. 支持Perl语言兼容的正则表达式(PCRE)文本处理。17. 具有内存垃圾自动收集的功能。当对象不再被引用时,它们所占用的内存空间自动被回收后再利用。18. 拥有对象、符号目录,供多人协作完成的大型软件项目,既可以引用他人的目标模块,又可以避免变量或函数重名的覆盖危险。19. 除了使用内建函数外,还可以通过导入共享库来进行功能扩展。 比如调用 windows 操作系统的库函数来实现GUI界面,使用 COM 对象、.NET 框架等等。20. TeaScript 可运用于分布计算、科学统计、图形与图像和人工智能领域。 HTTP、 TCP/IP 和UDP 套节字界面使得它很容易编写网络应用程序。
  • [互动交流] http获取到的json怎么转成对象存储
    {    "status": 1,    "data": {        "category": [{            "title": "产经",            "url": "",            "subcat": [{                    "title": "消费",                    "url": "",                    "type": "5"                },                {                    "title": "医药",                    "url": "",                    "type": "5"                }            ],            "type": 1        }]    }}各位老师我刚开始接触arkts开发,我用http获取到了json数据,但是本地要使用的话得存起来,我想到的是存到对象里面,但是找了好多资料都没有搞定,哪位老师有时间帮忙教导一下,我用了class-transformer也没搞定,基础太差了,谢谢路过的老师
  • [技术干货] C#冒泡排序-专注
     一、冒泡排序基本原理  冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。  以一个简单的整数数组为例,假设数组为[5, 4, 3, 2, 1]。第一轮比较时,首先比较第一个元素5和第二个元素4,因为5>4,所以交换它们的位置,数组变为[4, 5, 3, 2, 1]。接着比较第二个元素5和第三个元素3,因为5>3,交换后数组变为[4, 3, 5, 2, 1],以此类推。经过第一轮比较(总共比较n-1次,n是数组元素个数),最大的元素5就会 “浮” 到数组的最后面。然后进行第二轮比较,此时不需要比较最后一个元素了,因为它已经是最大的。经过n-1轮这样的比较,数组就会排序完成。  二、C#实现冒泡排序的代码示例  以下是一个简单的C3方法来实现的冒泡排序,用于对一个整数数组进行排序:   在上述代码中:  BubbleSort方法接受一个整数数组array作为参数。首先获取数组的长度n。  外层循环for (int i = 0; i < n - 1; i++)控制排序的轮数,总共需要n-1轮。  内层循环for (int j = 0; j < n - i - 1; j++)用于每一轮比较元素。在每一轮中,比较相邻的元素,如果array[j]>array[j + 1],就交换它们的位置。交换元素的操作通过一个临时变量temp来实现。  在Main方法中,首先定义了一个未排序的整数数组numbers,然后调用BubbleSort方法对其进行排序,最后使用foreach循环输出排序后的数组元素。  C#练习26 ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/2408_89166609/article/details/144719919 
  • [技术干货] python常见运算符及用法小结【转】
    算术运算符运算符描述+两个数相加两个数相加,或是字符串连接-两个数相减*两个数相乘,或是返回一个重复若干次的字符串/两个数相除,结果为浮点数%取模,返回两个数相除的余数//两个数相除,返回商的整数部分**幂运算,返回乘方结果1234567print(1 + 2)  # 3print(2 - 1)  # 1print(2 * 3)  # 6print(3 / 2)  # 1.5print(6 % 5)  # 1print(8 // 2)  # 4print(3 ** 2)  # 9如果想同时得到商和余数,可以用divmod这个方法该方法的返回值是tuple (x//y, x%y).1print(divmod(10,3)) # (3,1)因为浮点数精度的问题,Python还存在一些计算方面的小问题1print(0.1+0.1+0.1-0.3)  # 5.551115123125783e-17要解决这个问题,可以导入decimal模块123from decimal import Decimal# 计算结果:0.0print(Decimal('0.1')+Decimal('0.1')+Decimal('0.1')-Decimal('0.3'))关系运算符运算符描述==比较对象是否相等!=比较对象是否不相等>大于,例如a>b,将比较a与b的大小,a>b返回True,否则返回False<小于,例如a<b,将比较a与b的大小,a<b返回True,否则返回False>=大于等于,例如a>=b,将比较a与b的大小,a>=b返回True,否则返回False<=小于等于,例如a<=b,将比较a与b的大小,a<=b返回True,否则返回False12345678a = 10b = 20print(a == b)  # Falseprint(a != b)  # Trueprint(a > b)  # False print(a < b)  # Trueprint(a >= b)  # Falseprint(a <= b)  # True1.返回值为bool值12print(True == 1)  # Trueprint(False == 0)  # True==比较数值(int与str不能直接比较)12print(2.0 == 2)  # Trueprint('2' == 2)  # False字符串与字符串之间是比较ASCII值12# Trueprint('abc' < 'xyz') # 97 98 99 < 120 121 122连续比较,python的解释机制123print(3 > 2 > 1)  # Trueprint(3 > 2 > 2)  # Falseprint((3 > 2) > 1) # False赋值运算符运算符描述=常规赋值运算符,将运算结果赋值给变量+=加法赋值运算符,例如 a+=b 等效于 a=a+b-=减法赋值运算符,例如 a-=b 等效于 a=a-b*=乘法法赋值运算符,例如 a*=b 等效于 a=a*b/=除法赋值运算符,例如 a/=b 等效于 a=a/b//=取整除赋值运算符,例如 a//=b 等效于 a=a//b%=取模赋值运算符,例如 a%=b 等效于 a=a%b**=幂运算赋值运算符,例如 a**=b 等效于 a=a*b123a = 1       # 将等号右边 赋值 等号左边a = a + 1   # 先等号右边计算 再赋值给 等号左边a += 1      # a = a + 1逻辑运算符运算符描述and与运算,如果a 为False,a and b返回False 否则返回y的计算值or或运算,如果a非0,返回a的值,否则返回b的值not非运算,如果a为True,返回False,如果a为False,返回True12345a = 10b = 20print(a and b)  # 20print(a or b)  # 10print(not a)  # Falsea and b 两者都为True时结果才为Truea or b 两者有一个为True则结果就为True短路(懒惰)原则False and True 当and运算符时,遇到第一个为False则不会往后了True or False 当or运算符时,遇到第一个为True则不会往后了成员运算符运算符描述in如果在指定的序列中找到值返回True,否则返回Falsenot in如果在指定的序列中找到值返回True,否则返回False123456list1 = [1, 2, 3, 4, 5]a = 1if a in list1:    print("a是list1的元素之一")else:    print("a不是list1的元素")身份运算符运算符描述is判断两个标识符是不是引用自一个对象is not判断两个标识符是不是引用自不同对象 is 和比较运算符 == 的区别 is 用于判断两个变量是否引自同一个对象(可使用id()查看),而 ==用于判断变量的值是否相等!1234567a = [1, 2, 3]b = [1, 2, 3]# 可通过id()查看内存地址print(id(a))  # 2042443551304print(id(b))  # 2042443551816print(a is b)  # Falseprint(a == b)  # True1234567a = 2b = 2.0# 可通过id()查看内存地址print(id(a))  # 140722443350320print(id(b))  # 2336678499216print(a is b)  # Falseprint(a == b)  # True三目运算符三目运算符的表示方法:True_statements if expression else False_statements1234a = 1b = 2# a+b不大于3执行后面的else语句 b-a = 1print(a+b if a+b>3 else b-a)运算符优先级运算符描述**指数(最高优先级)*/%//乘,除,取模和取整除±加法减法<= >=比较运算符== !=等于运算符= %= 、= 、、=-= += *= **=赋值运算符is is not身份运算符in not in成员运算符not or and逻辑运算符
  • [技术干货]  calc(四则运算)不起作用
    用于动态计算长度值。需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);任何长度值都可以使用计算值()函数进行计算;calc()函数支持“+”,“ - ”,“*”,“/”运算;计算值()函数使用标准的数学运算优先级规则;calc()不起作用应该是运算符前后没留空格导致,可以加空格测试
  • [技术干货] 新手小白学JAVA 面向对象之多态[转载]
    1. 概念多态是面向对象程序设计(OOP)的一个重要特征,指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。比如,你的女盆友让你买点水果回来,不管买回来的是苹果还是西瓜,只要是水果就行,这个就是生活中多态的体现再比如,小猫、小狗、小猪我们可以把他们都归纳成小动物,每种小动物都需要吃东西,所以我们可以统一设置他们都必须吃,但是每种小动物的习性不一样,那这个就可以设置成小动物自己特有的功能,多态对象只能调用父类中定义子类中重写的功能,并不能调用子类的特有功能,这样就实现了代码的统一2 . 特点多态的前提1:是继承多态的前提2:要有方法的重写父类引用指向子类对象,如:Animal a = new Cat();多态中,编译看左边,运行看右边3. 练习:多态入门案例创建包: cn.tedu.oop创建类: TestDemo.javapackage cn.tedu.oop2;/*本类用作多态的入门案例*/public class TestDemo {    public static void main(String[] args) {        //6.创建“纯纯的”对象用于测试        Animal a = new Animal();        Cat c = new Cat();        Dog d = new Dog();        a.eat();//小动物Animal吃啥都行~调用的是父类自己的功能        c.eat();//小猫爱吃小鱼干~调用的是子类重写后的功能        d.eat();//小狗爱吃肉骨头~调用的是子类重写后的功能        /*2.父类对象不可以使用子类的特有功能*/        //a.jump();//报错,Animal类里并没有这个方法        //a.run();//报错,Animal类里并没有这个方法        c.jump();//小猫Cat跳的老高啦~,子类可以调用自己的功能        d.run();//小狗Dog跑的老快啦~,子类可以调用自己的功能        //7.创建多态对象进行测试        /*3.口诀1:父类引用指向子类对象        * 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/        Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存        Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存        //8.测试多态对象        /*4.口诀2:编译看左边,运行看右边        * 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型        *      必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/        a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体    }}/*1.多态的前提:继承+重写*///1.创建父类class Animal{    //3.创建父类的普通方法    public void eat(){        System.out.println("小动物Animal吃啥都行~");    }}//2.1创建子类1class Cat extends Animal{    //4.1添加重写的方法    public void eat(){        System.out.println("小猫爱吃小鱼干~");    }    //5.1添加子类的特有功能    public void jump(){        System.out.println("小猫Cat跳的老高啦~");    }}//2.2创建子类2class Dog extends Animal{    //4.2添加重写的方法    @Override    public void eat(){        System.out.println("小狗爱吃肉骨头~");    }    //5.2添加子类的特有功能    public void run(){        System.out.println("小狗Dog跑的老快啦~");    }}4. 多态的好处多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法提高了程序的可扩展性和可维护性5. 多态的使用前提:多态对象把自己看做是父类类型成员变量: 使用的是父类的成员方法: 由于存在重写现象,所以使用的是子类的静态成员: 随着类的加载而加载,谁调用就返回谁的6. 练习:多态成员使用测试创建包: cn.tedu.oop创建类: TestDemo2.javapackage cn.tedu.oop2;/*本类用于测试多态成员的使用情况*/public class TestDemo2 {    public static void main(String[] args) {        //7.创建纯纯的子类对象        Dog2 d = new Dog2();        System.out.println(d.sum);//20,子类自己的属性        d.eat();//小狗爱吃肉包子,子类自己的方法        //8.创建多态对象        /*口诀1:父类引用指向子类对象*/        /*口诀2:编译(保存)看左边,运行(效果)看右边*/        Animal2 a = new Dog2();        /*多态中,成员变量使用的是父类的*/        System.out.println(a.sum);//10        /*多态中,方法的声明使用的是父类的,方法体使用的是子类的*/        a.eat();//小狗爱吃肉包子        /*多态中,调用的静态方法是父类的,因为多态对象把自己看作是父类类型        * 直接使用父类中的静态资源*/        a.play();//没有提示,玩啥都行~        Animal2.play();    }}//1.创建父类class Animal2{    //3.创建父类的成员变量    int sum = 10;    //4.创建父类的普通方法    public void eat(){        System.out.println("吃啥都行~");    }    //9.1定义父类的静态方法play    public static void play(){        System.out.println("玩啥都行~");    }}//2.创建子类class Dog2 extends Animal2{    //5.定义子类的成员变量    int sum = 20;    //6.重写父类的方法    @Override    public void eat(){        System.out.println("小狗爱吃肉包子");    }    //9.2创建子类的静态方法play    //@Override    /*这不是一个重写的方法,只是恰巧在两个类中出现了一模一样的两个静态方法    * 静态方法属于类资源,只有一份,不存在重写的现象    * 在哪个类里定义,就作为哪个类的资源使用*/    public static void play(){        System.out.println("小狗喜欢玩皮球~");    }}7 拓展7.1 设计汽车综合案例创建包: cn.tedu.oopexec创建类: DesignCar.javapackage cn.tedu.oop2;/*本类用于完成汽车设计案例*/public class DesignCar {    public static void main(String[] args) {        //9.创建一个纯纯的父类对象进行测试        Car c = new Car();        System.out.println(c.getColor());//null        c.start();        c.stop();        //c.swim();//报错,父类对象不可以调用子类的特有功能        //10.创建纯纯的子类对象做测试        BMW b = new BMW();        System.out.println(b.color);//五彩斑斓的黑        System.out.println(b.getColor());//null        b.start();//都让开,我的车要起飞啦~        b.stop();//唉呀妈呀熄火了~        //11.创建多态对象进行测试        Car c2 = new TSL();        //System.out.println(c2.color);        System.out.println(c2.getColor());        c2.stop();        c2.start();        //c2.swim();    }}//1.通过分析,抽象形成一个汽车类class Car{    //2.定义并封装汽车类的属性--成员变量    private String brand;//品牌    private String color;//颜色    private int id;//编号    private double price;//价格    //3.定义功能    public void start(){        System.out.println("我的小车车启动啦~");    }    public void stop(){        System.out.println("唉呀妈呀熄火了~");    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }}//4.创建子类class BMW extends Car{    String color = "五彩斑斓的黑";    //5.重写父类的方法    @Override    public void start(){        System.out.println("都让开,我的车要起飞啦~");    }}//6.创建子类2class TSL extends Car{    //7.重写父类的方法    @Override    public void stop(){        System.out.println("唉呀妈,怎么停不下来呢");    }    //8.添加子类的特有功能    public void swim(){        System.out.println("没想到吧,我还是个潜水艇");    }}7.2 多态为了统一调用标准package cn.tedu.oop2;public class TestFruit {    public static void main(String[] args) {        Fruit f = new Fruit();        Apple a = new Apple();        Orange o = new Orange();        get(f);        get(a);        get(o);    }    //只需要创建一个方法,就可以执行截然不同的效果    //忽略子类对象的差异统一看作父类类型    public static void get(Fruit f){        f.clean();    }}class Fruit{    public void clean(){        System.out.println("水果要洗洗再吃");    }}class Apple extends Fruit{    @Override    public void clean(){        System.out.println("苹果需要削皮");    }}class Orange extends Fruit{    @Override    public void clean(){        System.out.println("橙子需要剥皮");    }}7.3 静态变量和实例变量的区别在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。7.4 向上转型和向下转型在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型。向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。比如:父类Parent,子类Child父类的引用指向子类对象:Parent p=new Child();说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其他资源使用的还是父类型的。比如:花木兰替父从军,大家都把花木兰看做她爸,但是实际从军的是花木兰,而且,花木兰只能做她爸能做的事,在军营里是不可以化妆的。向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象Parent p = new Child();//向上转型,此时,p是Parent类型Child c = (Child)p;//此时,把Parent类型的p转成小类型Child其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。比如:花木兰打仗结束,就不需要再看做是她爸了,就可以”对镜贴花黄”了————————————————版权声明:本文为CSDN博主「程序媛 泡泡」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_43884234/article/details/116593803
  • [技术干货] 初识C语言(中篇)[转载]
    10. 操作符算数操作符+        -        *        /        %算数操作符中的+ - *和平常运算方法相似,我们在这边重点介绍 / 和 %运算符/ 操作符为了让我们的讲解更加具有针对性,我们分正数和负数两部分进行讲解:/ 操作符对正数#include<stdio.h>int main(){    int a = 7 / 2;    printf("%d\n", a);//3}分析:对于上方代码当我们用平时的逻辑,那么这个答案应该是3.5,可在程序中编译运行,结果是 3,我们不禁产生疑惑是不是因为你打印的结果是整形的缘故,其实本身结果还是3.5呢?让我们用代码验证:#include<stdio.h>int main(){    float f = 7 / 2;    printf("%f\n",f);//3.000000}可当我们再次进行编译运行时,结果是3.000000,因此我们可以得出结论:除号两端的操作数如果都是整数,执行的是整数除法,至少有一个操作数是浮点数,执行的才是浮点数的除法!!!对于正数是这样进行运算的,那么负数呢?/ 操作符对负数#include<stdio.h>int main(){    int i = -2.9;    int j = 2.9;    printf("%d\n",j);//-2    printf("%d\n",j);//2    return 0;}对于负数运算,我们打印 j 的值,结果为 -2 ,和正数运算规律相似,我们可以看出它们运算都是向0取整的,那么如何理解呢?对于取整,当正负数进行运算时,并不会出现四舍五入的情况,无论正数负数都是向0方向取整!(-2.9向零取整得到2)如下图所示:小科普在C语言中,是不是只有一种取整方式?如果有它们分别是怎么实现的?接下来我们来一一了解:trunc - 取整函数#include<math.h>int main(){     printf("%d\n",(int)trunc(-2.9));//-2      printf("%d\n",(int)trunc(2.9));//2  }Tips:由于trunc函数默认接收的返回值为%f,但是我们这边想输出的是整数所以强制类型转化成int类型。floor - 地板取整#include<stdio.h>#include<math.h>int main(){    printf("%.lf\n",floor(-2.9));//-3    printf("%.lf\n",floor(-2.1));//-3    printf("%.lf\n",floor(2.9));//2    printf("%.lf\n",floor(2.1));//2}因为其取整方式和函数名,我们称它为地板取整,什么意思呢,我们编译结果发现负数-2.9的值变成了-3,对于正数2.9的值变成了2。我们可以观察到无论是正数还是负数,在用floor函数进行取整的时候都是变小,我们观察其本质可以总结为-∞取整,如下图所示:ceil - +∞取整#include<stdio.h>int main(){    printf("%.lf\n",ceil(-2.9));//-2    printf("%.lf\n",ceil(-2.1));//-2    printf("%.lf\n",ceil(2.9));//3    printf("%.lf\n",ceil(2.1));//3}当我们编译运行程序,可以观察到负数-2.9变为-2,-2.1变为-2,正数2.9变为3,2.1变为3。我们可以观察到ceil函数的取整,结果都会在原来的基础上变大一个整数位,我们总结出该取整方式为+∞取整,如下图所示:round - 四舍五入取整是的你没有看错,与我们平常思维方式相同的四舍五入取整来了,上代码:#include<math.h>int main(){    printf("%.lf\n",round(-2.9));//-3    printf("%.lf\n",round(-2.1));//-2    printf("%.lf\n",round(2.9));//3    printf("%.lf\n",round(2.1));//2}对于这种取整方式,没什么好说的,就是按照我们平时的思路来,例如当值2.9时,值为3,当值为2.1时,值为2。在当前情况下,凡取整的值大于等于2.5,得出的结果都会变为3。% 操作符概念:如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ r < d。其中,q 被称为商,r 被称为余数。对于此部分我们依旧是从正数和负数两方面进行剖析:% 操作符对正数#include<stdio.h>int main(){    int a = 10;    int d = 3;    printf("%d\n",a%d);//1    //因为:a=10,d=3,q=3,r=1 0<=r<d(3)    //所以:a=q*d+3 -> 10=3*3+1    return 0;}-代码:基于概念,我们可以理解当前代码的意思(详情见注释)。但我们还有另一种理解方式:% 操作符,关注的是除法后的余数,例如代码中的10%3,我们也可以理解为商3余1,相对于概念,这种方式更加容易接受一些。Warning:操作符两端的操作数必须是整数!!!% 操作符对负数int main(){    int a = - 10;    int d= 3;    printf("%d\n",a%d);//-1} 很显然,结果不满足定义中的0<=r<d,故后来就有了一个修订版的定义:如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r| < |d|。其中,q 被称为商,r 被称为余数。根据定义,这里的结果也能解释了,即-10 = (-3)*3+(-1)。在C语言中,%本质为取余,余数的大小,本质取决于商q的,而商都取决于除法运算的取整规则。在对于正数的取余和取模在C语言中是相同的,我们发现对于向0取整和向-∞的取整在正数上是同向的,但是对于负数上就完全不同了,因此我们平时遇到的大多都是整数取模,并没有做太多解释。移位操作符>>        <<(以后讲解)位操作符&         ^(以后讲解)赋值操作符=        +=        -=        *=        /=        &=        ^=        |=        >>=由于赋值操作符便于理解,我们挑两个讲一下(详情见注释):int main(){    int a = 10;//创建变量,并初始化    a = 20;//赋值    a = a+5//等价于 a+=5    a = a-5//等价于 a-=5}单目操作符!                 逻辑反操作-                 负值+                正值&                取地址sizeof         操作数的类型长度(以字节为单位)~                对一个数的二进制按位取反--                前置、后置--++              前置、后置++*                 间接访问操作符(解引用操作符)(类型)         强制类型转换我们常见的操作符比如+都有两个操作数,表示为左操作数+右操作数,这种操作符叫做双目操作符。单目操作符其实就是只有一个操作数的。在这里,对于!,-,+等操作符都便于理解,而对于&和*我打算之后在指针部分讲解,这里我们着重讲一下--,和++操作符(详情见注释):#include<stdio.h>int main(){    int a = 10;    int b = ++a;//前置++,先++后使用    //a=a+1,b=a    printf("a=%d b=%d\n",a,b);//11 11    ---------------------------------    int a = 10;    int b = a++;//后置++,先使用,后++    //b=a,a=a+1    printf("a=%d b=%d\n",a,b);//11 10    ---------------------------------    int a = 10;    int b = --a;//前置--,先--后使用    //a=a-1,b=a    printf("a=%d b=%d\n",a,b);//9 9    ---------------------------------    int a = 10;    int b = a--;//后置--,先使用,后--    //b=a,a=a-1    printf("a=%d b=%d\n",a,b);//10 9}关系操作符>         >=         <        <=        !=(不相等)        ==(相等)前几个操作符,也就是对应的大于,大于等于,小于,小于等于等比较关系的操作符,这里我们讲一下后两个操作符。例1int main(){    int a = 3;    int b = 3;    if(a!=b)    {        printf("hehe\n");        }    if(a==b)    {        printf("haha\n");        }    //结果为hehe}运行结果如下: 观察代码,很简单,判断a和b是否相等,如果相等则输出haha,若不相等输出hehe,因为c此处a和b都等于3,所以打印结果为hehe。例2#include<stdio.h>int main(){    char arr1[] = "abcdef";    char arr2[] = "abcdef";    if(arr1==arr2)    {        printf("==\n");        }    else    {        printf("!=\n");        }}我们知道用==和!=可以判断是否相等,那么对于字符串呢?他们是否相等,当我们编译后,发现它们是不相等的!因为arr1和arr2是字符串首元素地址,开辟的空间不同,所以地址当然不同,如果要比较两个字符串的大小可以用strcmp函数,接下来看修改后的代码:#include<stdio.h>#include<string.h>int main(){    char arr1[] = "abcdef";    char arr2[] = "abcdef";    if(strcmp(arr1,arr2)==0)    {        printf("==\n");        }    else    {        printf("!=\n");        }}再次运行:对于strcmp这个函数使用时需要应用头文件#include<string.h>,如果返回的值为0,则两个字符串相等。 逻辑操作符&& - 逻辑与 - 并且        || - 逻辑或 - 或者int main(){    int a= 3;    int b = 0;    int c = a && b;    printf("%d\n",c);//真为1,假为0    if(a&&b)    {        printf("hehe\n");        }    if(a||b)    {        printf("haha\n);    }}运行得:分析:&&的返回值是这样规定的,如果两个数都为真,则值为1,反之则为0。对于本代码由于a&&b为0,故不打印hehe,||的值是有一个为真则为真,值为1,反之为0。这里由于a||b为真,所以打印haha。条件操作符exp1?exp2:exp3#include<stdio.h>int main(){    int a = 10;    int b = 0;    b = (a>5?3:-3);    printf("%d\n",b);//3    return 0;}分析:条件操作符使用时先判断表达式1,如果表达式1结果为真,则输出第一个值,否则为第二个值,改题中因为a>10,所以打印结果为3。当然,这段代码也可以用if        else语句来表示:#include<stdio.h>int main(){    int a = 10;    int b = 0;    if(a>5)    {        b=3;        }    else    {        b=-3;        }    printf("%d\n", b);}逗号表达式exp1, exp2, exp3, …expN#include<stdio.h>int main(){    int a=3;    int b=5;    int c=0;    int d= (a+=2,b=b-c+a,c=a+b);    //      a=5   b=10   c=5+10             printf("%d\n",d);}分析:对于逗号表达式其特点为从左往右依次计算,整个表达式的结果是最后一个表达式的结果,因此在代码中d的值也就是15。下标引用、函数调用和结构成员[]        ()        .        ->对于这类操作符我们讲解一下[ ]操作符:#include<stdio.h>int main(){    int arr[10] = {0};    arr[4]=5;    return 0;}分析:对于上述代码就是引用下标4,将arr[4]的位置上赋值5。和一些操作符相同,[ ]也有两个操作数,例如arr 和 4是两个操作数,对于这个代码写成4[arr]也可以,但是这种写法不仅让人难以理解,而且比较挫,我们可千万不要写出这样的代码!!!11. 常见关键字C 语言标准中规定了32个关键字,而在之后C99的标准下又增加了五个关键字,anduin这次对大家进行归纳的是C标准中的32个关键字,我们根据其特性,可以把它分为几类:  数据类型关键字(12个)char:声明字符型变量或函数short:声明短整型或函数Int :声明整型变量或函数long :声明长整型变量或函数signed:声明有符号类型变量或函数unsigned:声明无符号整形变量或函数foat:声明浮点型变量或函数double:声明双精度变量或函数struct:声明结构体变量或函数union:声明共用体(联合)数据类型enum:声明枚举类型void:声明函数无返回值或无参数,声明无类型指针控制语句关键字(12个)1.循环控制(5个)for:一种循环语句do:循环语句的循环体while :循环语句的循环条件break:跳出当前循环continue:结束当前循环,开始下一轮循环2.条件语句(3个)if:条件语句else:条件语句否定分支goto:无条件跳转语句3.开关语句(3个)switch:用于开关语句case:开关语句分支default:开关语句中的"其他"分支4.返回语句(1个)return:函数返回语句(可以带参数,也可以不带参数)5.存储类型关键字(5个)auto:声明自动变量,一般不使用extern:声明变量实在其他文件中声明register:声明寄存器变量static:声明静态变量typedef:用以给数据类型取别名(但是该关键字被分到存储关键字分类中,虽然看起来没什么相关性)注意:存储关键字,不可以同时出现,也就是说,在一个变量定义的时候,只能有一个。6.其它关键字(3个)const:声明只读变量sizeof:计算数据类型长度volatile:说明变量在程序执行中可被隐含地改变这里anduin带大家有选择性的,讲解几个关键字,若没有讲到日后我们一一讲解:autoauto 从字面意思来看就是自动的意思 它也被成为自动变量局部变量都是自动创建,自动销毁的,所以局部变量都是auto修饰的。int main(){    auto int a = 10;//局部变量都是auto类型的,因此auto基本会被省略    return 0;}typedef本质本质:类型重命名使用方法#include<stdio.h>typedef unsignde int u_int;int main(){    u_int x = 0;     return 0;}分析:当我们在写代码时,一些代码类型很长,例如无符号整型unsigned int或者结构体,指针等,这时我们就可以用typedef对它进行类型重命名,本段代码中就是用了typedef来重命名unsigned int为u_int。作用对类型重命名的一种解决方案,让我们在面临冗长的类型命名方面上更加简便,可以对一些不太好理解的数据类型进行简化。register我们先想想,数据在计算机上可以存放在哪里呢?1.内存2.硬盘3.高速缓存4.寄存器存储金字塔寄存器存在的本质从硬件层面上,提高计算机的运算效率。当读取数据时,计算器先去寄存器中读取,如果没有读取到,再去高速缓存区中读取,最后才是内存,而且在cpu再读取寄存器中的数据时,内存->高数缓存区(cache),cache->寄存器,这个数据传递过程会持续进行,大大提高效率!register 修饰变量也就是相同的原理,尽量把所修饰变量,放入CPU寄存区中,从而达到提高效率的目的。#include<stdio.h>int main(){    register int a = 10;    return 0;}register 修饰什么变量register可不是什么变量都适合修饰的,要知道寄存器的价格是很昂贵的,register所修饰的变量也得"精挑细选"一番。局部变量(全局变量由于其特性会导致CPU寄存器被长时间占用)不会被写入的(写入就需要写回内存,register本身就是快速读取,后续还要读取检测的话,就与原目的背道而驰了)高频被读取的变量(俗话说把钱用在刀刃上,存入了寄存器,当然要经常使用的)如果要使用,不要大量使用,寄存器的数量是有限的!小科普register修饰的变量,不能取地址!!!#include<stdio.h>int main(){    register int a = 0;     printf("&a = %p\n", &a);    return 0;}编译运行: 分析:因为register的作用,变量a已经被放入寄存器中了,你怎么取地址呢?结语以上就是初识C语言中篇的内容,虽然只有两个专题,但是内容其实也是很多的,希望我的文章对你有帮助,如果大家觉得anduin写的还可以的话,请点赞+收藏哦!你们的肯定就是对我最大的鼓励!今天也是高考第一天,祝广大学子辛勤奋战在学海,汗水扬起成功帆!愿大家都可以金榜题名!————————————————版权声明:本文为CSDN博主「ExplorerAnduin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/m0_67867172/article/details/125163589
  • [交流吐槽] 函数
    1、函数的优点:(1)复用代码(2)隐藏实现细节(3)提高可维护性(4)提高可读性便于调试2、函数的创建:def 函数名([输入参数])函数体[return xxx]3、函数的参数传递:(1)函数调用时的参数传递:位置实参:根据形参对应的位置进行实参传递,位置对应例如def fuc1(a,b),调用时fuc1(10,20)关键字实参:根据形参名称进行实参传递,例如def fuc1(a,b),调用时fuc1(b=10,a=20)(2)如果是不可变对象,在函数体内的修改不会影响实参的值如果是可变对象,在函数体内的修改会影响实参的值4、函数的返回值:(1)函数返回多个值时,结果为元组(2)函数返回一个值时,结果为原值(3)函数没有返回值时,省略return5、函数的参数定义:(1)函数定义默认值参数:函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参。只传一个参数,未被定义的参数未默认值。默认值参数注意一定要放在其他需要传递实参的形参最后。(2)个数可变的位置参数:使用*定义,结果为一个元组,例如def fun1(*args)个数可变的关键字形参:使用**定义,结果为一个字典,例如def fun1(**args)如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。 Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
  • [技术干货] Lua基础之运算符的使用示例
    Lua分为主要三类运算符,分别是算术运算符,关系运算符,逻辑运算符,还有特殊运算符。1、算术运算符有: + (加)   -(减)   *(乘)  /(除)   %(取模)   ^(求幂)   -(符号)来看一个例子:test6.luanum1 = 4 ;num2 = 2 ;print(num1+num2);print(num1-num2);print(num1*num2);print(num1/num2);print(num1%num2);print(num1^num2);print(-num1);解释运行:lua test6.lua结果:6282.0016.0-42、关系运算符有: ==(等于)   ~=(不等于)  >(大于)  <(小于)  >=(大于等于)  <=(小于等于)当比较结果成立返回true,否则返回false来看一个例子: test6.luanum = 1 ;num1 = 1;num2 = 2;num3 = 3; num4 = 4;num5 = 5;num6 = 6;ret = num1 == num2 ;print(ret);ret = num1 ~= num2 ; print(ret);ret = num3 > num2 ;print(ret);ret = num4 < num3 ; print(ret);ret = num5 >= num6 ;print(ret);ret = num1 <= num ;print(ret);解释运行:lua test6.lua结果:falsetruetruefalsefalsetrue3、逻辑运算符有: and(逻辑与)   or(逻辑或)   not(逻辑非)假设有A和B,如果A and B, 为真返回A,为假返回B 假设有A和B ,如果A or  B , 为真返回A ,为假返回B假设有A和B ,如果 not A  , 为真返回true ,为假返回false来看一个例子:test6.luanum1 = 100 ;num2 = 200 ;num3 = 0 ;ret = num1 and num3 ; print(ret);ret = num1 or num3 ; print(ret);ret = not num1 ;print(ret);ret = not(num1 and num2);print(ret);解释运行:lua test6.lua结果:0100falsefalse4、特殊运算符 .. 表示连接两个字符串     #表示返回字符串或者表的长度(注意,这里的长度不包括'\0')案例: test6.lua解释运行: lua test6.lua--定义两个字符串str1 = "Hello";str2 = "World";--连接两个字符串ret = str1..str2;print(ret);--获取连接后的字符串的长度str_length = #ret ;print(str_length);结果:HelloWorld10当然,lua的运算符也是有优先级的,优先级从高到底的顺序为:^  not   -(负号)  *  /  +  -  ..  <  >  <=  >=   ~=  ==  and or
  • [技术干货] 《看漫画学Python》笔记系列:三. 数字类型的数据;四.运算符
    上一章: 一.准备出发 二.编程基础    三. 数字类型的数据1.Python中的数据类型               python中有6种主要的内置数据类型:数字、字符串、列表、元组、集合和字典。               *列表、元组、集合和字典都是容器类型,只不过容器之间的内部结构不同。              不同的数据类型在计算机内部存储时会有所不同。不同的数据类型有时候不兼容,需要进行类型转换才可以计算,相同的数据类型是可以进行计算的2. 数字类型              有4种数字类型:整数类型、浮点类型、复数类型和布尔类型。              (1)整数类型为int类,表示的是不带小数的数字。有四种进制表示方式,分别是十进制、二进制、八进制和十六进制。              (2)浮点类型为float类,有两种表示方式,一是小数,二是科学技术法。              (3)复数类型为complex类。              在计算机中被表示为a+bj,其中a称为实部,b称为虚部,j称为虚数单位。              两个复数可以进行相加,实部和实部相加,虚部和虚部相加,形成新的复数。              (4)布尔类型为bool类,只有两个值:True和False              布尔类型属于整数类型,或说布尔类型是整数类型的一个子类。              Python任何类型的数据都可以通过bool()函数转换为布尔值,那些“没有的”、“空的”值会被转换成False,反之转换为True。3. 数字类型的相互转换              两种:隐式类型转换(自动转换)、显式类型转换(非自动)              比如,使用布尔类型的函数转换就是显式类型转换              <1>隐式类型的装换              看一个例子              <2>显式类型的装换              除复数外,三种数字类型如整数、浮点和布尔都有自己的转换函数,分别是int()、float()、和bool()函数    四.运算符1.算术运算符              主要是针对数字类型的运算,但是有些运算符也可以用于字符串以及列表类型的运算。              *注意除和地板除法区别,除结果为float类型,地板除法结果为整数类型。注意下述例子中负数的地板除,注意True的大小写,注意True被当作整数1参与运算。2.比较运算符              也称为关系运算符,结果为布尔值,即True或False              注意下方例子中浮点数与整数都可以进行比较3.逻辑运算符              “逻辑与”与“逻辑或”具有短路特征              注意下方例子,在不进行短路计算,结果不确定时,f1()函数会被调用。而在进行短路计算,有确定结果时,f1()函数不会被调用。【def f1():  #定义一个函数,冒号后为函数内容】5.位运算符              在计算机中,数据按照字节进行存放,1个字节为8位二进制数,此8位二进制数可以按位进行计算。              (1) ~ 取反 ,二进制数,不是0就是1,0取反就是1,1取反就是0。但!错啦!具体运算比较复杂,涉及到原码、补码、反码的问题。                   公式:~a = (a + 1) x -1 ,比如下面例子中a十进制数9,则~a为-10,如a十进制数为-9,则~a为10                   ❶ 所以,你知道正负数的原码、补码、反码分别如何计算吗?❷你知道在上述9和-10的例子中,按位取反具体是如何运算的吗?              【请耐心阅读,文末为大家解答哦~】              (2) & :如果两个位都为1的情况下,结果为1,只要一个为0,结果就位0              (3)  | :只有一个为1的情况下,结果就为1              (4)  ^ :如果一个是0,一个是1,结果就是1;如果都是为1,或者都是为0,结果为0              (5)>>右移:按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1              如  00001010>>2=00000010;   10001010>>3=11110001              右移一位相当于除2,右移n位相当于除以2的n次方。这里是取商哈,余数就不要了。              (6)<< 左移:按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。              要求右操作数必须是非负值,在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。              若a=15,即二进制数00001111,左移2位得00111100,没有1溢出,则左移两位相当于15乘2^2,15<< 2=60,即乘了4,即十进制数60。以下是左移两位溢出的高位中包含1的情况,64<<2为256。127<<2为5086.赋值运算符7.运算符的优先级———————————————————————————————————今天的学习就到这里,一起来看下帖中的2个问题。❶ 问:你知道正负数的原码、补码、反码分别如何计算吗?首选请注意分清下概念:取反:逻辑非“!”,逻辑取反, false变true,true变false,在C中,只要不是0就是真,所以!5值是0反码:正数的反码是其本身,对于负数其符号位不变其它各位取反(0变1,1变0)按位取反(~): 按位取反1变0,0变1。好了,现在解决问题疑问,请看机器数、真值、原码、反码、补码的相关定义1、机器数一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1.比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。那么,这里的 00000011 和 10000011 就是机器数。2、真值机器数的第一位是符号位,后边才是真正的数值,所以机器数的形式值就不等于真正的数值。例如上面的有符号数10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值 = +000 0001 = +11000 0001的真值 = –000 0001 = –13. 原码原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。比如如果是8位二进制:[+1](原码) = 0000 0001[-1](原码) = 1000 0001第一位是符号位。因为第一位是符号位,所以8位二进制数的取值范围就是:[1111 1111 , 0111 1111]。即[-127 , 127]原码是人脑最容易理解和计算的表示方式。4. 反码反码的表示方法是: 正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反。[+1] = [00000001](原码)= [00000001](反码)[-1] = [10000001](原码)= [11111110](反码)可见如果一个反码表示的是负数,人脑无法直观的看出来它的数值。通常要将其转换成原码再计算。5. 补码补码的表示方法是:正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1 (即在反码的基础上+1)。[+1] = [00000001](原码) = [00000001](反码) = [00000001](补码)[-1] = [10000001](原码) = [11111110](反码) = [11111111](补码)对于负数,补码表示方式也是人脑无法直观看出其数值的。通常也需要转换成原码在计算其数值。❷你知道在上述例子中,按位取反具体是如何运算的吗?如何得到9按位取反为-10,10按位取反为-9的?(1)正数9按位取反——>(~9),计算步骤如下:正数原码=反码=补码所以9的原码/反码/补码: 0000 1001对补码取反 1111 0110(符号位一起取反)对其取反码: 1000 1001(符号位不变)取补码: 1000 1010(反码+1)最终结果  1000 1010,即-10(2)负数-10按位取反——>(~10)正数原码=反码=补码-10 原码:1000 1010-10反码: 1111 0101(符号位不变)-10补码: 1111 0110(反码+1)补码取反:0000 1001(符号位一起取反)正好得到一个整数,正数原码、反码、补码都一样所以最后结果 0000 1001,二进制为-9特殊:0按位取反,即(~0)为-1总结:按位取反公式:~a = (a + 1) x -1下一章:...
  • [交流吐槽] 隐式的类类型转换(转换构造函数)
    如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数又叫转换构造函数(converting constructor)。能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则。只允许 一步类类型转换抑制构造函数定义的隐式转换将构造函数声明为 explicit加以阻止explicit关键字只允许出现在类内的构造函数声明处(只对一个实参的构造函数有效)explicit构造函数只能用于直接初始化,不能将explicit构造函数用于拷贝形式的初始化过程。Sales_data item1(null_book);   //正确,直接初始化Sales_data item2 = null_book;  //错误:不能将 explicit 构造函数用于拷贝形式的初始化过程尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们可以使用这样的构造函数 显式地强制进行转换。
  • [其他] 基于OpenCV的条形码区域分割
    分割是识别图像内一个或多个对象的位置的过程。我们要介绍的技术其实非常简单,它利用了形态算子的扩张和侵蚀,以及诸如开运算,闭运算和黑帽算子的组合。01.简介安装Anaconda后,让我们从Anaconda的提示符下使用以下命令转到OpenCV安装:conda install -c https://conda.anaconda.org/menpo opencv现在,让我们从Anaconda启动器启动Spyder IDE。Anaconda启动器一旦运行了Spyder,建议验证OpenCV安装是否成功。在Python控制台的右下角,我们进行以下测试:import cv2代码讲解我们已经创建了一个启动GitHub存储库。小伙伴可以使用以下方法直接克隆它:git clone --branch step1 https://github.com/lucapiccinelli/BarcodesTutorial.git现在,我们将要下载测试图像,并对他们进行读取和显示。import cv2 import matplotlib.pyplot as plt im = cv2.imread(r’img\barcodes.jpg’, cv2.IMREAD_GRAYSCALE) plt.imshow(im, cmap=’Greys_r’)接下来,我们将对图像进行二值化处理,这样可以通过阈值的设定来提取出我们感兴趣的部分。使用黑帽运算符,我们可以增加较暗的图像元素。我们可以首先使用简单的全局阈值安全地对图像进行二值化处理。黑帽运算符使我们可以使用非常低的阈值,而不必过多地关注噪声。在应用blackhat时,我们使用的内核会更加重视垂直图像元素。内核具有固定的大小,因此可以缩放图像,这也可以提高性能(并支持某种输入归一化)。黑帽+阈值处理它遵循其他形态运算符的采用,顺序地将它们组合在一起以获得条形码位置中的连接组件。#riscalatura dell'immagine scale = 800.0 / im.shape[1] im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale))) #blackhat kernel = np.ones((1, 3), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel, anchor=(1, 0)) #sogliatura thresh, im = cv2.threshold(im, 10, 255, cv2.THRESH_BINARY)膨胀和闭合的这种组合在测试图像上效果很好,但可能无法在其他图像上达到相同的效果。这没有关系,大家可以尝试改变参数和运算符的组合,直到对结果满意为止。膨胀+闭运算最后的预处理步骤是应用具有很大内核的开运算符,以删除太少而无法适合条形码形状的元素。kernel = np.ones((21, 35), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)这是我们希望得到的最终结果:使用35x21内核打开现在,我们可以运行连接的组件的检测算法,并检索带有坐标和尺寸的条形码矩形。如大家在上一张图像中所看到的那样,最后的形态学步骤并未滤除全部的噪声。但是,在这种情况下,将它们过滤掉非常简单,以矩形区域值作为阈值就可以了。#rilettura dell'immagine, stavolta a colori im_out = cv2.imread(r'img\barcodes.jpg') #estrazione dei componenti connessi contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) unscale = 1.0 / scale if contours != None: for contour in contours: # se l'area non è grande a sufficienza la salto if cv2.contourArea(contour) <= 2000: continue #estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo) rect = cv2.minAreaRect(contour) #l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate rect = \ ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \ (int(rect[1][0] * unscale), int(rect[1][1] * unscale)), \ rect[2]) #disegno il tutto sull'immagine originale box = np.int0(cv2.cv.BoxPoints(rect)) cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness = 2) plt.imshow(im_out) #scrittura dell' immagine finale cv2.imwrite(r'img\out.png', im_out)最后,在上面的代码中,我使用提取的矩形绘制它们,并将其覆盖在原始图像上。最终结果,条形码以绿色框突出显示。结论• 提出的技术非常简单有效,但存在一些令人讨厌的缺点:• 它对条形码偏斜非常敏感;它可以很好地工作到大约45度,然后您必须执行第二遍,修改内核的方向。• 它只能在固定尺寸范围内找到条形码。• 尽管对矩形区域施加了过滤,但仍有可能无法清除某些非条形码。第一个和第二个可能不是真正的问题,但是最后一个可能会花费大家大量时间来尝试解码非条形码的内容。一个很好的解决方案是将条形码特征(图像梯度,傅立叶变换)输入给神经网络(或一些其他一些分类器),并在第二时刻过滤掉噪声。
  • [技术干货] Xpath语法格式总结
    经常在工作中会使用到XPath的相关知识,但每次总会在一些关键的地方不记得或不太清楚,所以免不了每次总要查一些零碎的知识,感觉即很烦又浪费时间,所以对XPath归纳及总结一下。在这篇文章中你将能学习到:XPath简介XPath 路径表达式详解XPath在DOM,XSLT及XQuery中的应用XPath简介XPath是W3C的一个标准。它最主要的目的是为了在XML1.0或XML1.1文档节点树中定位节点所设计。目前有XPath1.0和XPath2.0两个版本。其中Xpath1.0是1999年成为W3C标准,而XPath2.0标准的确立是在2007年。W3C关于XPath的英文详细文档请见:http://www.w3.org/TR/xpath20/ 。XPath是一种表达式语言,它的返回值可能是节点,节点集合,原子值,以及节点和原子值的混合等。XPath2.0是XPath1.0的超集。它是对XPath1.0的扩展,它可以支持更加丰富的数据类型,并且XPath2.0保持了对XPath1.0的相对很好的向后兼容性,几乎所有的XPath2.0的返回结果都可以和XPath1.0保持一样。另外XPath2.0也是XSLT2.0和XQuery1.0的用于查询定位节点的主表达式语言。XQuery1.0是对XPath2.0的扩展。关于在XSLT和XQuery中使用XPath表达式定位节点的知识在后面的实例中会有所介绍。在学习XPath之前你应该对XML的节点,元素,属性,原子值(文本),处理指令,注释,根节点(文档节点),命名空间以及对节点间的关系如:父(Parent),子(Children),兄弟(Sibling),先辈(Ancestor),后代(Descendant)等概念有所了解。这里不在说明。XPath路径表达式在本小节下面的内容中你将可以学习到:路径表达式语法相对/绝对路径表达式上下文谓词(筛选表达式)及轴的概念运算符及特殊字符常用表达式实例函数及说明这里给出一个实例Xml文件。下面的说明及实例都是基于该XML文件。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465<?xml version="1.0" encoding="UTF-8"?><!-- edited with XMLSpy v2008 rel. 2 sp2 (http://www.altova.com ) by Administrator --><?xml-stylesheet type="text/xsl" href="messages.xsl" rel="external nofollow" ?><messages> <message id="1"> <sender>gukaitong@gmail.com</sender> <to>anonymous@gmail.com <group name="IT"> <address>111@gmail.com</address> <address>222@gmail.com</address> <address>aaa@gmail.com</address> <address>bbb@gmail.com</address> <address>ccc@gmail.com</address> </group> </to> <subject>This is a sample</subject> <datetime date="2008-12-11" time="12:00:00" formatted="12/11/2008 12:00AM">2008-12-11T12:00:00Z</datetime> <body> Are you interested in?  <attachments> <attachment id="1">  <message id="0">  <sender>anonymous@gmail.com</sender>  <to>gukaitong@gmail.com</to>  <body>We strongly recommend the following books  <books xmlns:amazon="http://www.amazon.com/books/schema ">  <amazon:book>   <name>Professional C# 2008 </name>   <country>USA</country>   <price>37.79</price>   <year>2007</year>  </amazon:book>  <amazon:book>   <name>Microsoft Visual C# 2008 Step by Step </name>   <country>USA</country>   <price>26.39 </price>   <year>2008</year>  </amazon:book>  <amazon:book>   <name>C# in Depth</name>   <country>USA</country>   <price>29.69 </price>   <year>2006</year>  </amazon:book>  <amazon:book>   <name>Thinking in Java</name>   <country>USA</country>   <price>23.69 </price>   <year>2004</year>  </amazon:book>  </books>  </body>  </message> </attachment> </attachments> </body> </message> <message id="2"> <sender>333@gmail.com</sender> <to>444@gmail.com</to> <subject>No title</subject> <body/> </message></messages>路径表达式语法:路径 = 相对路径 | 绝对路径XPath路径表达式 = 步进表达式 | 相对路径 "/"步进表达式。步进表达式=轴 节点测试 谓词说明:其中轴表示步进表达式选择的节点和当前上下文节点间的树状关系(层次关系),节点测试指定步进表达式选择的节点名称扩展名,谓词即相当于过滤表达式以进一步过滤细化节点集。谓词可以是0个或多个。多个多个谓词用逻辑操作符and, or连接。取逻辑非用not()函数。请看一个典型的XPath查询表达式:/messages/message//child::node()[@id=0],其中/messages/message是路径(绝对路径以"/"开始),child::是轴表示在子节点下选择,node()是节点测试表示选择所有的节点。[@id=0]是谓词,表示选择所有有属性id并且值为0的节点。相对路径与绝对路径:如果"/"处在XPath表达式开头则表示文档根元素,(表达式中间作为分隔符用以分割每一个步进表达式)如:/messages/message/subject是一种绝对路径表示法,它表明是从文档根开始查找节点。假设当前节点是在第一个message节点【/messages/message[1]】,则路径表达式subject(路径前没有"/")这种表示法称为相对路径,表明从当前节点开始查找。具体请见下面所述的"表达式上下文"。表达式上下文(Context):上下文其实表示一种环境。以明确当前XPath路径表达式处在什么样的环境下执行。例如同样一个路径表达式处在对根节点操作的环境和处在对某一个特定子节点操作的环境下执行所获得的结果可能是完全不一样的。也就是说XPath路径表达式计算结果取决于它所处的上下文。XPath上下文基本有以下几种:当前节点(./):如./sender表示选择当前节点下的sender节点集合(等同于下面所讲的"特定元素",如:sender)父节点(../):如../sender表示选择当前节点的父节点下的sender节点集合根元素(/):如/messages表示选择从文档根节点下的messages节点集合.根节点(/*):这里的*是代表所有节点,但是根元素只有一个,所以这里表示根节点。/*的返回结果和/messages返回的结果一样都是messages节点。递归下降(//):如当前上下文是messages节点。则//sender将返回以下结果:/messages//sender :<sender>gkt1980@gmail.com</sender><sender>111@gmail.com</sender><sender>333@gmail.com</sender>/messages/message[1]//sender:<sender>gkt1980@gmail.com</sender><sender>111@gmail.com</sender>我们可以看出XPath表达式返回的结果是:从当前节点开始递归步进搜索当前节点下的所有子节点找到满足条件的节点集。特定元素如sender:表示选择当前节点下的sender节点集合,等同于(./sender)注意:在执行XPath时一定要注意上下文。即当前是在哪个节点下执行XPath表达式。这在XMLDOM中很重要。如:在XMLDOM中的selectNodes,selectSingleNode方法的参数都是一个XPath表达式,此时这个XPath表达式的执行上下文就是调用这个方法的节点及它所在的环境。更多信息请参见:http://www.w3.org/TR/xpath20/谓词(筛选表达式)及轴的概念:XPath的谓词即筛选表达式,类似于SQL的where子句.轴名称结果ancestor选取当前节点的所有先辈(父、祖父等)ancestor-or-self选取当前节点的所有先辈(父、祖父等)以及当前节点本身attribute选取当前节点的所有属性child选取当前节点的所有子元素。descendant选取当前节点的所有后代元素(子、孙等)。descendant-or-self选取当前节点的所有后代元素(子、孙等)以及当前节点本身。following选取文档中当前节点的结束标签之后的所有节点。namespace选取当前节点的所有命名空间节点parent选取当前节点的父节点。preceding直到所有这个节点的父辈节点,顺序选择每个父辈节点前的所有同级节点preceding-sibling选取当前节点之前的所有同级节点。self选取当前节点。运算符及特殊字符:运算符/特殊字符说明/此路径运算符出现在模式开头时,表示应从根节点选择。//从当前节点开始递归下降,此路径运算符出现在模式开头时,表示应从根节点递归下降。.当前上下文。..当前上下文节点父级。*通配符;选择所有元素节点与元素名无关。(不包括文本,注释,指令等节点,如果也要包含这些节点请用node()函数)@属性名的前缀。@*选择所有属性,与名称无关。:命名空间分隔符;将命名空间前缀与元素名或属性名分隔。( )括号运算符(优先级最高),强制运算优先级。[ ]应用筛选模式(即谓词,包括"过滤表达式"和"轴(向前/向后)")。[ ]下标运算符;用于在集合中编制索引。|两个节点集合的联合,如://messages/message/to | //messages/message/cc-减法。div,浮点除法。and, or逻辑运算。mod求余。not()逻辑非=等于!=不等于特殊比较运算符< 或者 &lt;<= 或者 &lt;=> 或者 &gt;>= 或者 &gt;=需要转义的时候必须使用转义的形式,如在XSLT中,而在XMLDOM的scripting中不需要转义。常用表达式实例:/Document Root文档根./*选择文档根下面的所有元素节点,即根节点(XML文档只有一个根节点)/node()根元素下所有的节点(包括文本节点,注释节点等)/text()查找文档根节点下的所有文本节点/messages/messagemessages节点下的所有message节点/messages/message[1]messages节点下的第一个message节点/messages/message[1]/self::node()第一个message节点(self轴表示自身,node()表示选择所有节点)/messages/message[1]/node()第一个message节点下的所有子节点/messages/message[1]/*[last()]第一个message节点的最后一个子节点/messages/message[1]/[last()]Error,谓词前必须是节点或节点集/messages/message[1]/node()[last()]第一个message节点的最后一个子节点/messages/message[1]/text()第一个message节点的所有子节点/messages/message[1]//text()第一个message节点下递归下降查找所有的文本节点(无限深度)/messages/message[1] /child::node()/messages/message[1] /node()/messages/message[position()=1]/node()//message[@id=1] /node()第一个message节点下的所有子节点//message[@id=1] //child::node()递归所有子节点(无限深度)//message[position()=1]/node()选择id=1的message节点以及id=0的message节点/messages/message[1] /parent::*Messages节点/messages/message[1]/body/attachments/parent::node()/messages/message[1]/body/attachments/parent::* /messages/message[1]/body/attachments/..attachments节点的父节点。父节点只有一个,所以node()和* 返回结果一样。(..也表示父节点. 表示自身节点)//message[@id=0]/ancestor::*Ancestor轴表示所有的祖辈,父,祖父等。向上递归//message[@id=0]/ancestor-or-self::*向上递归,包含自身//message[@id=0]/ancestor::node()对比使用*,多一个文档根元素(Document root)/messages/message[1]/descendant::node()//messages/message[1]//node()递归下降查找message节点的所有节点/messages/message[1]/sender/following::*查找第一个message节点的sender节点后的所有同级节点,并对每一个同级节点递归向下查找。//message[@id=1]/sender/following-sibling::*查找id=1的message节点的sender节点的所有后续的同级节点。//message[@id=1]/datetime/@date查找id=1的message节点的datetime节点的date属性//message[@id=1]/datetime[@date]//message/datetime[attribute::date]查找id=1的message节点的所有含有date属性的datetime节点//message[datetime]查找所有含有datetime节点的message节点//message/datetime/attribute::*//message/datetime/attribute::node()//message/datetime/@*返回message节点下datetime节点的所有属性节点//message/datetime[attribute::*]//message/datetime[attribute::node()]//message/datetime[@*]//message/datetime[@node()]选择所有含有属性的datetime节点//attribute::*选择根节点下的所有属性节点//message[@id=0]/body/preceding::node()顺序选择body节点所在节点前的所有同级节点。(查找顺序为:先找到body节点的顶级节点(根节点),得到根节点标签前的所有同级节点,执行完成后继续向下一级,顺序得到该节点标签前的所有同级节点,依次类推。)注意:查找同级节点是顺序查找,而不是递归查找。//message[@id=0]/body/preceding-sibling::node()顺序查找body标签前的所有同级节点。(和上例一个最大的区别是:不从最顶层开始到body节点逐层查找。我们可以理解成少了一个循环,而只查找当前节点前的同级节点)//message[@id=1]//*[namespace::amazon]查找id=1的所有message节点下的所有命名空间为amazon的节点。//namespace::*文档中的所有的命名空间节点。(包括默认命名空间xmlns:xml)//message[@id=0]//books/*[local-name()='book']选择books下的所有的book节点,注意:由于book节点定义了命名空间<amazone:book>.若写成//message[@id=0]//books/book则查找不出任何节点。//message[@id=0]//books/*[local-name()='book' and namespace-uri()='http://www.amazon.com/books/schema']选择books下的所有的book节点,(节点名和命名空间都匹配)//message[@id=0]//books/*[local-name()='book'][year>2006]选择year节点值>2006的book节点//message[@id=0]//books/*[local-name()='book'][1]/year>2006指示第一个book节点的year节点值是否大于2006.返回xs:boolean: true函数及说明:值得欣喜的是XPath函数和XSLT,XQuery等共享函数库,函数库为我们提供了功能丰富的各种函数的调用,我们也可以自定义自己的函数。这里不再对每个函数的用法逐一说明,中文的可以参考这个网站, https://www.jb51.net/w3school/xpath/index.htm XPath在DOM,XSLT及XQuery中的应用DOM:123456789101112131415161718192021<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd "><html xmlns="http://www.w3.org/1999/xhtml "><head><title>XPath Test</title></head><body><script language="javascript" type="text/javascript">var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async="false";xmlDoc.load("messages.xml");xmlDoc.setProperty("SelectionLanguage", "XPath"); var sPath = "/messages/message[1]//books/*[local-name()='book']";var bookNodes = xmlDoc.selectNodes(sPath);document.write("<ul>");for ( var i = 0; i < bookNodes.length; i++) {document.write("<li>" + bookNodes[i].childNodes[0].text + "</li>");}document.write("</ul>");</script></body></html>注意:我们若使用new ActiveXObject("Microsoft.XMLDOM")则需要注意的是:因为早期的XMLDOM的SelectionLanguage属性默认是正则表达式,不是XPath语言。所以需要指定这样一条语句xmlDoc.setProperty("SelectionLanguage", "XPath"); 以支持XPath查询表达式。.若没有指定SelectionLanguage属性值为XPath则要注意以下情况:数组下标从0开始(我们知道在XPath查询表达式中数组下标是从1开始的)不支持在XPath查询表达式中使用XPath函数。总结以上就是本文关于Xpath语法格式总结的全部内容,希望对大家有所帮助