皮皮网

皮皮网

【gradle wrapper源码】【Apollo源码阅读】【codesoso 源码搜索】conditional 源码

时间:2024-11-19 04:17:23 分类:知识

1.条件编译形式
2.Spring Boot小记
3.预编译命令行由什么符号开头?
4.从 A|B 得到 A&B

conditional 源码

条件编译形式

       条件编译形式允许程序在运行时根据特定条件选择执行不同的代码块。这种形式通常用于在不同平台或配置下优化代码或实现兼容性。以 NNN 和 MMM 作为条件示例,其结构如下:

       #if NNN

       statement1;

       #elif MMM

       statement2;

       #else

       statement3;

       #endif

       此结构中,`#if`、`#elif` 和 `#else` 是gradle wrapper源码预处理器指令,用于根据 NNN 和 MMM 的值决定执行哪部分代码。当 NNN 为真(通常表示为1)时,执行 `statement1`;当 NNN 为假(通常表示为0)且 MMM 为真时,执行 `statement2`;当 NNN 和 MMM 均为假时,则执行 `statement3`。

       条件编译的Apollo源码阅读形式在软件开发中非常有用。它允许开发者在不修改源代码的情况下,针对不同环境或配置提供不同功能。例如,在编写跨平台应用时,可以使用条件编译来根据目标平台的特性选择使用特定的功能库或功能实现。这有助于减少代码冗余,提高代码效率和可维护性。

       此外,条件编译还能用于在开发过程中进行调试和测试。通过条件地启用或禁用某些功能或代码块,开发者可以更容易地定位和解决问题。codesoso 源码搜索在生产环境中,可以使用条件编译来禁用调试代码、日志记录或性能测试代码,从而减少应用程序的大小和运行时消耗。

       总之,条件编译是一种强大的工具,能够根据运行环境和需求动态地调整程序的行为。它简化了代码维护和跨平台开发的过程,有助于提高软件的性能和可移植性。

扩展资料

       一般情况下,源程序中所有的miniblink网页源码行都参加编译。但有时希望对其中一部分内容只在满足一定条件下才进行编译,即对一部分内容指定编译条件,这就是“条件编译”(conditional compile)。条件编译语句排版时,需考虑以下三种位置:1)条件编译语句块与函数定义体之间不存在相互嵌套(主要在(.h)文件中);2)条件编译语句块嵌套在函数体之外(主要在(.c)文件中);3)条件编译语句嵌套在函数体内 (主要在(.c)文件中)。条件编译指令将决定那些代码被编译,而哪些是不被编译的。可根据表达式的值或某个特定宏是否被定义来确定编译条件。

Spring Boot小记

        1、ApplicationContextInitializer,在Spring上下文被刷新之前进行初始化的操作。这个时候已经创建了ApplicationContext ,但是没有refresh(),ApplicationContextInitializer对ApplicationContext进行初始话操作。

        2、SpringApplicationRunListener,对ApplicationContext的运行各个时期的事件进行广播,时事件能够被ApplicationListener所监听到。

        3、Runner,Spring上下文后置处理 Runners可以是两个接口的实现类: org.springframework.boot.ApplicationRunner org.springframework.boot.CommandLineRunner 其实没有什么不同之处,除了接口中的run方法接受的参数类型是不一样的以外。一个是封装好的ApplicationArguments类型,另一个是直接的String不定长数组类型。因此根据需要选择相应的接口实现即可。

        SpringBoot启动的时候,不论调用什么方法,都会构造一个SpringApplication的实例,然后调用这个实例的run方法,这样就表示启动SpringBoot。

        在run方法调用之前,也就是构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:

        SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:

        在@SpringBootApplication标签中引入了EnableAutoConfigurationImportSelector,其中调用了selectImports()方法,方法中调用org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector#getCandidateConfigurations方法,使用SpringFactoryLoader把META-INF文件夹中的spring.factories文件中EnableAutoConfiguration为key的文件加载了。 加载的文件全部都是java config配置文件(有默认配置),利用@Conditional(Class<? extends Condition>[]) 标签,对相应的bean进行选择性的加载。

        比较基本而且重要的一个类,运行加载了MATE-INF中的spring.factories 文件

        @Conditional标签是全部Conditional相关标签的根源。 源码中Conditional标签使用的是ConditionEvaluator来解析,如下 org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class<?>, java.lang.String, java.lang.Class<? extends java.lang.annotation.Annotation>...) org.springframework.context.annotation.ConditionEvaluator#shouldSkip(org.springframework.core.type.AnnotatedTypeMetadata, org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase)

        在初始化AnnotationConfigApplicationContext的时候,对ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等类进行了注册。如下

        ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor,所以会对BeanDefinitionRegistry或者BeanDefinition创建之后进行后置加工(refresh方法中,已经创建了BeanFactory,具体到运行到哪里看源码)。

        import解析原理根据的是ConfigurationClassPostProcessor,ConfigurationClassPostProcessor的加载过程参考上面 主要分析为啥@import标签是引入配置的但是却能够调用Selector的方法 org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>) org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors 接着如下,调用了selectImports方法

预编译命令行由什么符号开头?

       #号是官方定义的,用于和其他类型区别的,不用多考虑,吴健 源码你就看看我给你的链接看看官方的说法

       条件编译符号#define

       #if、#elif、#else 和 #endif 指令提供的条件编译功能是通过预处理表达式和条件编译符号来控制的。

       conditional-symbol:(条件符号:)

       除 true 和 false 外的任何标识符或关键字

       条件编译符号有两种可能的状态:已定义的或未定义的。在源文件词法处理开始时,条件编译符号除非已由外部机制(如命令行编译器选项)显式定义,否则是未定义的。当处理 #define 指令时,在指令中指定的条件编译符号在那个源文件中成为已定义的。此后,该符号就一直保持已定义的状态,直到处理一条关于同一符号的 #undef 指令,或者到达源文件的结尾。这意味着一个源文件中的 #define 和 #undef 指令对同一程序中的其他源文件没有任何影响。

       当在预处理表达式中引用时,已定义的条件编译符号具有布尔值 true,未定义的条件编译符号具有布尔值 false。不要求在预处理表达式中引用条件编译符号之前显式声明它们。相反,未声明的符号只是未定义的,因此具有值 false。

       条件编译符号的命名空间与 C# 程序中的所有其他命名实体截然不同。只能在 #define 和 #undef 指令以及预处理表达式中引用条件编译符号。

从 A|B 得到 A&B

       如何从 A|B 得到 A&B?

       Stack Overflow 上有相关答案。

       原因如下,我们来分解这个表达式:

       第一部分是 U extends any ? (k: U) => void : never

       第二部分是 extends ((k: infer I) => void) ? I : never

       第一部分中,U extends any 是什么意思,为什么要判断是否 extends any?

       具体可以参考这篇文章,简要来说,如果 extends 左边是联合类型,TypeScript 会将联合类型拆开进行判断。

       如果输入是 1|2,那么输出是 ((k: 1) => void) | ((k: 2) => void),而不是 (k: 1|2) => void,这样就得到了多个函数的联合。

       第二部分的意思是,如果左边是一个函数,那么就返回它的第一个参数的类型。

       那么问题来了,为什么 ((k: 1) => void) | ((k: 2) => void) 的参数是 1&2?

       因为函数参数是逆变的,我们假设有一个变量能同时传给 (k: 1) => void 和 (k: 2) => void,那么这个变量的类型应该是 1&2 而不是 1|2。

       A extends B 意味着所有 B 都可以无条件被 A 替换。

       一个函数能被 (k: 1) => void 和 (k: 2) => void 无条件替换,那么那个函数接受的参数必然既是1又是2。

       但是,根据 conditional type 的特性,((k: 1) => void) | ((k: 2) => void) 不是应该被分开处理吗?如果分开处理,结果依然会是 1|2。

       在苦思无果之后,TypeScript 核心贡献者@王文璐(也是 Vue 核心团队的成员)直接给我看了源码。

       虽然我看得不太懂,但大概意思是,extends 左边联合类型被拆开判断的情况只会出现在左边是一个类型参数的情况。

       大概就是 type F = T extends xxx 的这个左边会被拆开,而 type F = T|1 extends xxx 的左边就不会被拆开。

       我还是一头雾水。

       完。