首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

独家专栏 | 如何利用深度学习搭建一个最简单的无人驾驶系统

雷锋网按:本文为雷锋网独家专栏,作者系佐思产研研究总监周彦武,雷锋网(公众号:雷锋网)经授权发布。 国内最牛的无人驾驶厂家的运算平台是这样的: 一个英特尔至强 E5 的 CPU,拥有 12 内核,30MB 的二级缓存,运算能力为 400GOPS/s,功率消耗为 400 瓦(应该是第一代至强 E5,目前 E5 最高功率消耗都不超过 180 瓦),八个英伟达的 K80 GPU,每一个 K80 的运算能力为 8TOPS/s,通过 PCI-E 连接,每一个 K80 的功率消耗为 300 瓦,合计是 2800 瓦的功率,取得 64.4 TOPS/s 的运算能力。 和 Waymo 的车一样,需要一个备份系统,当然这个备份系统处于待机状态,功耗可能不到 500 瓦,但是为了有足够的冗余,同时还要考虑到传感器的功率消耗(传感器功率一般都很低,

优秀的个人博客,低调大师

阿里云轻量应用服务器,5分钟搭建wordpress个人博客

大家好,今天的博文,给大家介绍阿里云轻量服务器使用。首先,轻量服务器目前只支持linux系统,而博主只是个windows用户,因此在阿里云轻量服务器内测期,并没有对轻量服务器来兴趣。一直到内测送的体验券到期前两天,才懒散的按照官方文档试了一把。这一体验,感觉还不错,居然只需要2个命令即可上手。 具体操作进行之前,先把我的幸运券发给大家,20种产品首购可打折和享受优惠 【领券】http://wzfw.ltd/qjyl 【购买】轻量应用服务器http://wzfw.ltd/sas(本文重点) ECS,新用户独享199元一年http://wzfw.ltd/ecs199 ECS,新老用户3种自选一http://wzfw.ltd/ecs330 【抽奖】ECS首购大于百元http://wzfw.ltd/jiang 推荐结束,请看我下面的步骤: 1,领券选配购买(图1、2、3) 2,找管理台,由于是新机型,因此现在并不容易直接找到(图4) 3,轻量应用服务器,控制台介绍(图5、6) 4,开始配置,2个命令即可。其实只用第一个也行,拿到wordPress管理密码即可。(图7、8) 5,服务器配置完成,剩下的只需要登录WordPress后台配置即可(图9、10) 6,最终效果(图11) 原文地址:https://www.opengps.cn/Blog/View.aspx?id=40,文章的更新编辑依此链接为准。欢迎关注源站原创文章!

优秀的个人博客,低调大师

如何在阿里云服务器搭建FTP服务器?用FTP管理上传文件?

首先你需要买一个阿里云的ECS服务器,注意要买包年包月的,才会有公网IP. 购买阿里云服务器前,请先到阿里云官网 领取幸运券,然后再购买,除了价格上有很多优惠外,还可以参与抽奖。详见:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=2a7uv47d&utm_source=2a7uv47d 购买后,可以在本地电脑cmd控制台运行mstsc.exe启动远程桌面连接 计算机名输入ECS服务器的公网ip地址,开通了宽带的可以在控制台看到 点击连接如果提示输入用户名密码,用户名应该是administrator密码是对应的登录windows系统的密码(初始化的密码很复杂,包含大小写的那个) 成功连接 要是连接出现闪退的话可能是服务器那边没开机 或者处于待机状态 先去阿里云的连接管理终端动一下或者重启之后就可以了 接下来就可以在本地电脑直接操作ECS服务器了 下面进入正题 打开服务器默认的IE浏览器在网上下个FileZilla Server 安装过程自己可以问问度娘 安装完成后会跳出这个一个窗口 点击确定就好了,这边的服务器地址和端口是指连接服务器这台电脑的,和等下的自己的电脑连接服务器的时候的地址和端口是不一样的 确定之后进入主窗口 点击上面工具栏的小人图标建立一个用户(很重要) 点击用户下面的添加 输入用户名点击确定 勾选密码并输入,如111111 接下来先不要急着点确定 点击左边的shared folders选择要共享的文件夹 选完之后点击设为主目录 然后上面的用户读写权限看情况勾选 完成之后点左下角的确定就ok了 完成之后服务器的配置就好了 在本地电脑下载一个FlashFXP 运行之后的界面如下,左边的是本地电脑的文件系统,右边是连接的ftp服务器的文件系统 点击会话-快速连接 在地址中输入服务器的公网IP,端口号就是ftp默认的21不用改 用户名和密码填刚刚设置ftp服务器的时候的用户 也就是Test和111111 点击连接 连接成功了 上图是在将本地电脑的vs2012安装包上传到服务器中

优秀的个人博客,低调大师

04【在线日志分析】之Flume Agent的3台收集+1台聚合到hdfs的搭建

【log收集】:机器名称 服务名称 用户flume-agent-01: namenode hdfsflume-agent-02: datanode hdfsflume-agent-03: datanode hdfs 【log聚合】:机器名称 用户sht-sgmhadoopcm-01(172.16.101.54) root 【sink到hdfs】:hdfs://172.16.101.56:8020/testwjp/ 1.下载apache-flume-1.7.0-bin.tar.gz[hdfs@flume-agent-01 tmp]$ wget http://www-eu.apache.org/dist/flume/1.7.0/apache-flume-1.7.0-bin.tar.gz--2017-01-04 20:40:10-- http://www-eu.apache.org/dist/flume/1.7.0/apache-flume-1.7.0-bin.tar.gzResolving www-eu.apache.org... 88.198.26.2, 2a01:4f8:130:2192::2Connecting to www-eu.apache.org|88.198.26.2|:80... connected.HTTP request sent, awaiting response... 200 OKLength: 55711670 (53M) [application/x-gzip]Saving to: “apache-flume-1.7.0-bin.tar.gz” 100%[===============================================================================================================================================================================================>] 55,711,670 473K/s in 74s 2017-01-04 20:41:25 (733 KB/s) - “apache-flume-1.7.0-bin.tar.gz” saved [55711670/55711670] 2.解压重命名[hdfs@flume-agent-01 tmp]$ [hdfs@flume-agent-01 tmp]$ tar -xzvf apache-flume-1.7.0-bin.tar.gz [hdfs@flume-agent-01 tmp]$ mv apache-flume-1.7.0-bin flume-ng[hdfs@flume-agent-01 tmp]$ cd flume-ng/conf 3.拷贝flume环境配置和agent配置文件[hdfs@flume-agent-01 tmp]$ cp flume-env.sh.template flume-env.sh[hdfs@flume-agent-01 tmp]$ cp flume-conf.properties.template exec_memory_avro.properties 4.添加hdfs用户的环境变量文件[hdfs@flume-agent-01 tmp]$ cd[hdfs@flume-agent-01 ~]$ ls -latotal 24drwxr-xr-x 3 hdfs hadoop 4096 Jul 8 14:05 .drwxr-xr-x. 35 root root 4096 Dec 10 2015 ..-rw------- 1 hdfs hdfs 4471 Jul 8 17:22 .bash_historydrwxrwxrwt 2 hdfs hadoop 4096 Nov 19 2014 cache-rw------- 1 hdfs hdfs 3131 Jul 8 14:05 .viminfo[hdfs@flume-agent-01 ~]$ cp /etc/skel/.* ./cp: omitting directory `/etc/skel/.'cp: omitting directory `/etc/skel/..'[hdfs@flume-agent-01 ~]$ ls -latotal 36drwxr-xr-x 3 hdfs hadoop 4096 Jan 4 20:49 .drwxr-xr-x. 35 root root 4096 Dec 10 2015 ..-rw------- 1 hdfs hdfs 4471 Jul 8 17:22 .bash_history-rw-r--r-- 1 hdfs hdfs 18 Jan 4 20:49 .bash_logout-rw-r--r-- 1 hdfs hdfs 176 Jan 4 20:49 .bash_profile-rw-r--r-- 1 hdfs hdfs 124 Jan 4 20:49 .bashrcdrwxrwxrwt 2 hdfs hadoop 4096 Nov 19 2014 cache-rw------- 1 hdfs hdfs 3131 Jul 8 14:05 .viminfo 5.添加flume的环境变量[hdfs@flume-agent-01 ~]$ vi .bash_profile export FLUME_HOME=/tmp/flume-ngexport FLUME_CONF_DIR=$FLUME_HOME/confexport PATH=$PATH:$FLUME_HOME/bin[hdfs@flume-agent-01 ~]$ . .bash_profile 6.修改flume环境配置文件[hdfs@flume-agent-01 conf]$ vi flume-env.shexport JAVA_HOME=/usr/java/jdk1.7.0_25 7.将基于Flume-ng Exec Source开发自定义插件AdvancedExecSource的AdvancedExecSource.jar包上传到$FLUME_HOME/lib/http://blog.itpub.net/30089851/viewspace-2131995/ [hdfs@LogshedNameNodeLogcollector lib]$ pwd/tmp/flume-ng/lib[hdfs@LogshedNameNodeLogcollector lib]$ ll AdvancedExecSource.jar -rw-r--r-- 1 hdfs hdfs 10618 Jan 5 23:50 AdvancedExecSource.jar[hdfs@LogshedNameNodeLogcollector lib]$ 8.修改flume的agent配置文件[hdfs@flume-agent-01 conf]$ vi exec_memory_avro.properties# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1 # Describe/configure the custom exec sourcea1.sources.r1.type = com.onlinelog.analysis.AdvancedExecSourcea1.sources.r1.command = tail -f /var/log/hadoop-hdfs/hadoop-cmf-hdfs1-NAMENODE-flume-agent-01.log.outa1.sources.r1.hostname = flume-agent-01a1.sources.r1.servicename = namenode # Describe the sinka1.sinks.k1.type = avroa1.sinks.k1.hostname = 172.16.101.54a1.sinks.k1.port = 4545 # Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.keep-alive = 60 a1.channels.c1.capacity = 1000000a1.channels.c1.transactionCapacity = 2000 # Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 9.将flume-agent-01的flume-ng打包,scp到flume-agent-02/03 和 sht-sgmhadoopcm-01(172.16.101.54)[hdfs@flume-agent-01 tmp]$ zip -r flume-ng.zip flume-ng/* [jpwu@flume-agent-01 ~]$ scp /tmp/flume-ng.zip flume-agent-02:/tmp/[jpwu@flume-agent-01 ~]$ scp /tmp/flume-ng.zip flume-agent-03:/tmp/[jpwu@flume-agent-01 ~]$ scp /tmp/flume-ng.zip sht-sgmhadoopcm-01:/tmp/ 10.在flume-agent-02配置hdfs用户环境变量和解压,修改agent配置文件[hdfs@flume-agent-02 ~]$ cp /etc/skel/.* ./cp: omitting directory `/etc/skel/.'cp: omitting directory `/etc/skel/..'[hdfs@flume-agent-02 ~]$ vi .bash_profileexport FLUME_HOME=/tmp/flume-ngexport FLUME_CONF_DIR=$FLUME_HOME/confexport PATH=$PATH:$FLUME_HOME/bin[hdfs@flume-agent-02 ~]$ . .bash_profile [hdfs@flume-agent-02 tmp]$ unzip flume-ng.zip[hdfs@flume-agent-02 tmp]$ cd flume-ng/conf ##修改以下参数即可[hdfs@flume-agent-02 conf]$ vi exec_memory_avro.propertiesa1.sources.r1.command = tail -f /var/log/hadoop-hdfs/hadoop-cmf-hdfs1-DATANODE-flume-agent-02.log.outa1.sources.r1.hostname = flume-agent-02a1.sources.r1.servicename = datanode ###要检查flume-env.sh的JAVA_HOME目录是否存在 11.在flume-agent-03配置hdfs用户环境变量和解压,修改agent配置文件[hdfs@flume-agent-03 ~]$ cp /etc/skel/.* ./cp: omitting directory `/etc/skel/.'cp: omitting directory `/etc/skel/..'[hdfs@flume-agent-03 ~]$ vi .bash_profileexport FLUME_HOME=/tmp/flume-ngexport FLUME_CONF_DIR=$FLUME_HOME/confexport PATH=$PATH:$FLUME_HOME/bin[hdfs@flume-agent-03 ~]$ . .bash_profile [hdfs@flume-agent-03 tmp]$ unzip flume-ng.zip[hdfs@flume-agent-03 tmp]$ cd flume-ng/conf ##修改以下参数即可[hdfs@flume-agent-03 conf]$ vi exec_memory_avro.propertiesa1.sources.r1.command = tail -f /var/log/hadoop-hdfs/hadoop-cmf-hdfs1-DATANODE-flume-agent-03.log.outa1.sources.r1.hostname = flume-agent-03a1.sources.r1.servicename = datanode ###要检查flume-env.sh的JAVA_HOME目录是否存在 12.聚合端 sht-sgmhadoopcm-01,配置root用户环境变量和解压,修改agent配置文件[root@sht-sgmhadoopcm-01 tmp]# vi /etc/profileexport JAVA_HOME=/usr/java/jdk1.7.0_67-clouderaexport FLUME_HOME=/tmp/flume-ngexport FLUME_CONF_DIR=$FLUME_HOME/conf export PATH=$FLUME_HOME/bin:$JAVA_HOME/bin:$PATH[root@sht-sgmhadoopcm-01 tmp]# source /etc/profile[root@sht-sgmhadoopcm-01 tmp]# [root@sht-sgmhadoopcm-01 tmp]# unzip flume-ng.zip[root@sht-sgmhadoopcm-01 tmp]# cd flume-ng/conf [root@sht-sgmhadoopcm-01 conf]# vi flume-env.shexport JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera ###测试: 先聚合, sink到hdfs端[root@sht-sgmhadoopcm-01 conf]# vi avro_memory_hdfs.properties# Name the components on this agenta1.sources = r1a1.sinks = k1a1.channels = c1 # Describe/configure the sourcea1.sources.r1.type = avroa1.sources.r1.bind = 172.16.101.54a1.sources.r1.port = 4545 # Describe the sinka1.sinks.k1.type = hdfsa1.sinks.k1.hdfs.path = hdfs://172.16.101.56:8020/testwjp/a1.sinks.k1.hdfs.filePrefix = logsa1.sinks.k1.hdfs.inUsePrefix = . a1.sinks.k1.hdfs.rollInterval = 0### roll 16 m = 16777216 bytesa1.sinks.k1.hdfs.rollSize = 1048576a1.sinks.k1.hdfs.rollCount = 0a1.sinks.k1.hdfs.batchSize = 6000 a1.sinks.k1.hdfs.writeFormat = texta1.sinks.k1.hdfs.fileType = DataStream # Use a channel which buffers events in memorya1.channels.c1.type = memorya1.channels.c1.keep-alive = 90 a1.channels.c1.capacity = 1000000a1.channels.c1.transactionCapacity = 6000 # Bind the source and sink to the channela1.sources.r1.channels = c1a1.sinks.k1.channel = c1 13.后台启动[root@sht-sgmhadoopcm-01 flume-ng]# source /etc/profile[hdfs@flume-agent-01 flume-ng]$ . ~/.bash_profile [hdfs@flume-agent-02 flume-ng]$ . ~/.bash_profile [hdfs@flume-agent-03 flume-ng]$ . ~/.bash_profile [root@sht-sgmhadoopnn-01 flume-ng]# nohup flume-ng agent -c conf -f /tmp/flume-ng/conf/avro_memory_hdfs.properties -n a1 -Dflume.root.logger=INFO,console & [hdfs@flume-agent-01 flume-ng]$ nohup flume-ng agent -c /tmp/flume-ng/conf -f /tmp/flume-ng/conf/exec_memory_avro.properties -n a1 -Dflume.root.logger=INFO,console &[hdfs@flume-agent-01 flume-ng]$ nohup flume-ng agent -c /tmp/flume-ng/conf -f /tmp/flume-ng/conf/exec_memory_avro.properties -n a1 -Dflume.root.logger=INFO,console &[hdfs@flume-agent-01 flume-ng]$ nohup flume-ng agent -c /tmp/flume-ng/conf -f /tmp/flume-ng/conf/exec_memory_avro.properties -n a1 -Dflume.root.logger=INFO,console &14.校验:将集群的日志下载到本地,打开查看即可(略) ------------------------------------------------------------------------------------------------------------------------------------------------ 【备注】: 1.错误1 flume-ng安装的机器上没有hadoop环境,所以假如sink到hdfs话,需要用到hdfs的jar包[ERROR - org.apache.flume.node.PollingPropertiesFileConfigurationProvider$FileWatcherRunnable.run(PollingPropertiesFileConfigurationProvider.java:146)] Failed to start agent because dependencies were not found in classpath. Error follows.java.lang.NoClassDefFoundError: org/apache/hadoop/io/SequenceFile$CompressionType 只需在其他安装hadoop机器上搜索以下5个jar包,拷贝到$FLUME_HOME/lib目录即可。搜索方法: find $HADOOP_HOME/ -name commons-configuration*.jar commons-configuration-1.6.jarhadoop-auth-2.7.3.jarhadoop-common-2.7.3.jarhadoop-hdfs-2.7.3.jarhadoop-mapreduce-client-core-2.7.3.jarprotobuf-java-2.5.0.jarhtrace-core-3.1.0-incubating.jarcommons-io-2.4.jar 2.错误2 无法加载自定义插件的类 Unable to load source type: com.onlinelog.analysis.AdvancedExecSource2017-01-06 21:10:48,278 (conf-file-poller-0) [ERROR - org.apache.flume.node.PollingPropertiesFileConfigurationProvider$FileWatcherRunnable.run(PollingPropertiesFileConfigurationProvider.java:142)] Failed to load configuration data. Exception follows.org.apache.flume.FlumeException: Unable to load source type: com.onlinelog.analysis.AdvancedExecSource, class: com.onlinelog.analysis.AdvancedExecSource 执行hdfs或者root用户的环境变量即可[root@sht-sgmhadoopcm-01 flume-ng]# source /etc/profile[hdfs@flume-agent-01 flume-ng]$ . ~/.bash_profile [hdfs@flume-agent-02 flume-ng]$ . ~/.bash_profile [hdfs@flume-agent-03 flume-ng]$ . ~/.bash_profile

优秀的个人博客,低调大师

基础到实战:一文吃透 JS Tuples 与 Records 的所有核心用法

JavaScript 中的 Tuples(Tuples)与 Records(Records)提供了不可变的、基于值的数据结构,能简化状态管理、提升性能并增强代码的可预测性。 JavaScript 一直在持续进化以满足现代开发需求,其最新更新往往紧跟函数式编程和不可变数据处理的趋势。Tuples 与 Records 作为语言即将新增的两个特性,旨在简化不可变性的实现,同时提升开发效率与体验。本文将深入探讨这两个新特性,包括它们的设计目的、语法、优势及应用场景。 一、什么是 Tuples 与 Records? 1. Tuples(元组) Tuples 是不可变的有序值列表。和数组类似,Tuples 可以存储多个元素,但不可变性确保了数据一旦创建就无法修改------这保证了数据一致性,非常适合对数据完整性和可预测性要求高的场景。 2. Records(记录) Records 是不可变的键值对结构,类似 JavaScript 中的对象,但它是只读的:一旦创建,其属性和值就无法修改。 二、Tuples 与 Records 的核心特性 1. 不可变性(Immutability) Tuples 和 Records 都是完全不可变的,甚至嵌套元素也无法修改。 示例: const tuple = #[1, 2, 3]; const record = #{ name: "Alice", age: 25 }; // 以下操作都会抛出错误 tuple[0] = 99; // 错误:Tuples是不可变的 record.name = "Bob"; // 错误:Records是不可变的 2. 值语义(Value Semantics) 和数组、对象的"引用比较"不同,Tuples 与 Records 采用"值比较", equality 检查更符合直觉。 示例: const tuple1 = #[1, 2, 3]; const tuple2 = #[1, 2, 3]; console.log(tuple1 === tuple2); // true(值相同则相等) 3. 类型安全(Type Safety) Tuples 严格要求元素的顺序和类型一致性。结合 TypeScript 使用时,开发者可以定义明确的类型约束,进一步保证使用的可预测性。 4. 内存高效(Memory Efficiency) 不可变性让 JavaScript 引擎能优化内存使用:由于值永远不会改变,相同数据的引用可以在应用中重复利用,减少内存开销。 5. 语法(Syntax) Tuples 使用 #[...] 语法: const myTuple = #[1, 'hello', true]; Records 使用 #{...} 语法: const myRecord = #{ key: 'value', id: 123 }; 三、Tuples 与 Records 在 TypeScript 中的应用 即将推出的 Tuples 与 Records 能与 TypeScript 无缝集成,带来更强的类型安全、可预测性和可维护性。借助 TS 的强类型能力,这些不可变结构可以强制严格的数据格式,防止意外修改。 1. Tuples 的类型安全 TS 中的 Tuples 本就支持固定长度数组的类型校验,结合 JavaScript 的不可变 Tuples 后,安全性进一步提升。 示例:带类型的 Tuples 声明 const myTuple: #[number, string, boolean] = #[1, "hello", true]; // 合法访问 const num: number = myTuple[0]; // 允许 // 非法修改(Tuples不可变) myTuple[1] = "world"; // 错误:无法赋值给只读元素 核心优势: TS 确保元素遵循指定的类型顺序; 防止意外修改,维护数据完整性。 2. Records 的类型安全 Records 类似对象,但支持深层不可变。TS 的类型系统允许定义严格的键值结构,确保值在使用过程中始终一致。 示例:带类型的 Records 声明 const userRecord: #{ name: string, age: number, active: boolean } = #{ name: "Alice", age: 30, active: true }; // 类型安全的属性访问 const username: string = userRecord.name; // 尝试修改Records(会失败) userRecord.age = 31; // 错误:无法赋值给只读属性 核心优势: TS 强制严格的属性类型; 杜绝意外的属性修改。 3. TS 的类型推断 TS 能自动推断 Tuples 与 Records 的类型,减少显式注解的需求。 示例:类型推断 const config = #{ apiEndpoint: "https://api.example.com", retries: 3 }; // TS自动推断类型:#{ apiEndpoint: string, retries: number } console.log(typeof config.apiEndpoint); // "string" 4. 函数签名中的应用 Tuples 与 Records 非常适合作为函数的参数和返回值,确保输入输出符合预期结构。 示例 1:使用 Records 的函数 function getUserInfo(user: #{ id: number, name: string }): string { return `用户:${user.name}(ID:${user.id})`; } const user = #{ id: 101, name: "Bob" }; console.log(getUserInfo(user)); // 输出:用户:Bob(ID:101) 示例 2:返回 Tuples 的函数 function getCoordinates(): #[number, number] { return #[40.7128, -74.0060]; // 纽约坐标 } const coords = getCoordinates(); console.log(coords[0]); // 40.7128 5. 结合 TS 工具类型 TS 的工具类型(如Readonly、Pick、Partial)可以与 Tuples、Records 结合使用,增加灵活性。 示例:对 Records 使用Readonly type User = #{ id: number, name: string }; const readonlyUser: Readonly<User> = #{ id: 1, name: "Charlie" }; // 尝试修改Records readonlyUser.name = "David"; // 错误:无法修改只读属性 四、不同领域的实际应用场景 Tuples 与 Records 通过增强数据完整性、可预测性和效率,在多个行业中展现出独特优势。下面看看它们在不同领域的具体应用。 1. 金融应用 金融领域对数据完整性和不可变性要求极高,以防止未授权修改并符合监管标准。 示例:处理不可变的金融交易 const transaction: #{ id: number, amount: number, currency: string, completed: boolean } = #{ id: 12345, amount: 1000, currency: "USD", completed: false }; // 不修改原数据,创建处理后的新交易 const processedTransaction = #{ ...transaction, completed: true }; console.log(processedTransaction.completed); // true 行业优势: 防止交易数据被意外或未授权修改; 不可变性保证了审计追踪的可靠性。 2. 数据分析 处理大型数据集时,数据一致性至关重要。Tuples 可用于表示固定结构的报表数据。 示例:存储不可变的报表数据 const reportEntry: #[string, number, boolean] = #["销售额", 5000, true]; // 安全提取报表值 const [category, revenue, approved] = reportEntry; console.log(`分类:${category},收入:${revenue}`); 行业优势: 确保报表数据在处理过程中不被篡改; 便于 Records 的比较和去重。 3. 游戏开发 在游戏中,Tuples 可用于存储固定长度的数据,如坐标、RGB 颜色值或动画状态。 示例:用 Tuples 处理玩家坐标 const playerPosition: #[number, number] = #[100, 200]; // 移动玩家到新位置(创建新Tuples,而非修改原数据) const newPosition = #[200, 300]; console.log(`X:${playerPosition[0]}, Y:${playerPosition[1]}`); 行业优势: 固定长度、不可变的数据结构提升性能; 防止意外修改导致物理计算出错。 4. 配置管理 在大型应用中,Records 非常适合定义静态、不可修改的配置值。 示例:应用配置 const appConfig = #{ appName: "MyApp", maxUsers: 1000, theme: "dark" }; // 安全使用配置 console.log(appConfig.theme); // "dark" 行业优势: 防止关键配置被意外修改; 提升配置文件的可读性和可维护性。 5. 版本控制与数据一致性 对于需要向后兼容的应用,Records 能确保不同版本间的数据一致性。 示例:维护向后兼容 const oldVersionUser = #{ id: 1, name: "John" }; const newVersionUser = #{ ...oldVersionUser, email: "john@example.com" }; console.log(newVersionUser); // #{ id: 1, name: "John", email: "john@example.com" } 行业优势: 扩展数据结构时保持向后兼容; 维护旧版本时避免意外修改。 五、Tuples/Records vs Object.freeze():核心区别 Object.freeze() 和 Records 都能创建不可变数据结构,但在性能、深层不可变性、值语义和易用性上存在显著差异。选择哪种方式,取决于你的应用场景。 特性 Object.freeze() Records( Records) 不可变性 浅层(需手动实现深层冻结) 深层(自动实现) 语义比较 基于引用 基于值 性能 深层冻结时开销大 原生优化,效率高 语法 繁琐(需手动调用,嵌套需递归) 简洁(#{...} 原生语法) 1. 不可变性差异 Object.freeze():浅层不可变 Object.freeze() 只冻结对象的顶层属性,嵌套对象仍可修改,需手动递归冻结。 示例: const obj = { name: "Alice", address: { city: "New York" } }; // 冻结对象 Object.freeze(obj); // 尝试修改顶层属性(严格模式下报错) obj.name = "Bob"; // 静默失败或报错 // 嵌套属性仍可修改 obj.address.city = "Los Angeles"; // 成功 console.log(obj.address.city); // 输出:Los Angeles(已被修改) 修复方案:手动实现深层冻结函数 function deepFreeze(object) { Object.keys(object).forEach(key => { if (typeof object[key] === "object" && object[key] !== null) { deepFreeze(object[key]); // 递归冻结嵌套对象 } }); return Object.freeze(object); } const deeplyFrozenObj = deepFreeze(obj); deeplyFrozenObj.address.city = "San Francisco"; // 现在会报错 console.log(deeplyFrozenObj.address.city); // 输出:New York(未被修改) Records:深层不可变 Records 自动支持深层不可变,无需手动处理嵌套结构。 示例: const record = #{ name: "Alice", address: #{ city: "New York" } }; // 尝试修改任何属性都会报错 record.name = "Bob"; // 类型错误:无法赋值给只读属性 record.address.city = "Los Angeles"; // 类型错误:无法赋值给只读属性 console.log(record.address.city); // 输出:New York(未被修改) 核心结论 : Object.freeze() 需要手动递归实现深层不可变,而 Records 原生支持,更安全易用。 2. 引用比较 vs 值比较 Object.freeze():基于引用 冻结的对象仍按引用比较,即使内容相同,不同引用也视为不相等。 示例: const obj1 = Object.freeze({ name: "Alice" }); const obj2 = Object.freeze({ name: "Alice" }); console.log(obj1 === obj2); // 输出:false(引用不同) console.log(obj1.name === obj2.name); // 输出:true(值相同) Records:基于值 Records 按值比较,内容相同则视为相等,无论是否为不同实例。 示例: const record1 = #{ name: "Alice" }; const record2 = #{ name: "Alice" }; console.log(record1 === record2); // 输出:true(值相同) 核心结论 : Records 的值比较更符合直觉,避免了深层比较函数的繁琐。 3. 易用性与性能 更新方式:两者都需通过扩展语法创建新实例,但 Records 的语法更简洁; 性能:Object.freeze() 深层冻结时会有运行时开销,而 Records 是原生优化的不可变结构,性能更优; 语法体验:Records 的 #{...} 语法比手动调用 Object.freeze() 更直观,尤其处理嵌套结构时。 推荐场景 应用场景 推荐方案 简单的浅层不可变需求 Object.freeze()(小型对象) 复杂嵌套数据结构 Records(深层不可变) 频繁的值比较需求 Records(值语义更高效) 六、嵌套 Tuples 与 Records 1. 什么是嵌套结构? 嵌套 Tuples 是"包含其他 Tuples 的 Tuples",嵌套 Records 是"值为其他 Records 的 Records"------它们可以构建深层的不可变数据模型。 示例: const nestedTuple = #[ #[1, 2], #[3, 4] ]; const nestedRecord = #{ user: #{ name: "Alice", address: #{ city: "New York", zip: "10001" } } }; console.log(nestedTuple[0][1]); // 输出:2 console.log(nestedRecord.user.address.city); // 输出:"New York" 2. 为什么要用嵌套结构? 数据完整性:确保深层嵌套数据也不可变; 可预测性:值比较简化状态变化追踪; 可读性:清晰表达复杂的数据关系; 性能:不可变状态管理的内存使用更优。 3. 嵌套结构的更新:不可变原则 由于不可变性,更新嵌套结构需在每一层都使用扩展语法 创建新实例。 示例 1:更新嵌套 Records const user = #{ name: "Alice", details: #{ age: 30, address: #{ city: "Los Angeles", zip: "90001" } } }; // 深层更新城市(每一层都扩展) const updatedUser = #{ ...user, details: #{ ...user.details, address: #{ ...user.details.address, city: "San Francisco" } } }; console.log(updatedUser.details.address.city); // 输出:"San Francisco" 示例 2:用工具函数简化深层更新 // 深层更新Records的工具函数 function updateNestedRecord(record, keyPath, value) { if (keyPath.length === 1) { return #{ ...record, [keyPath[0]]: value }; } return #{ ...record, [keyPath[0]]: updateNestedRecord(record[keyPath[0]], keyPath.slice(1), value) }; } // 调用函数更新邮编 const updatedUserState = updateNestedRecord(user, ["details", "address", "zip"], "10002"); console.log(updatedUserState.details.address.zip); // 输出:"10002" 4. 常见陷阱与规避 陷阱 1:忘记逐层扩展 错误:const updatedUser = #{ ...user, details.address.city: "Seattle" };(语法错误) 解决:必须在每一层嵌套都使用扩展语法(如上面的示例)。 陷阱 2:错误的比较方式 错误:用 == 而非 === 比较 Records(虽然结果可能相同,但推荐用 === 符合值语义设计)。 解决:始终用 === 比较 Tuples/Records。 陷阱 3:访问不存在的嵌套属性 错误:console.log(user.details.phone.number);(phone 未定义,报错) 解决:用可选链 ?. 安全访问:user.details?.phone?.number ?? "未设置"。 七、与现代 JavaScript 模式的结合 Tuples 与 Records 天然契合以"不可变性"为核心的现代开发模式,尤其在状态管理中表现突出。 1. 在 Redux 中使用 Records import { createStore } from "redux"; // 用Records定义初始状态 const initialState = #{ user: #{ name: "Alice", loggedIn: false } }; const reducer = (state = initialState, action) => { switch (action.type) { case "LOGIN": // 不可变更新状态 return #{ ...state, user: #{ ...state.user, loggedIn: true } }; default: return state; } }; const store = createStore(reducer); store.dispatch({ type: "LOGIN" }); console.log(store.getState()); // 输出:#{ user: #{ name: "Alice", loggedIn: true } } 2. 在 React 中使用 Tuples 与 Records 示例 1:Records 作为 React 状态 import React, { useState } from 'react'; const UserProfile = () => { // 用Records存储用户状态 const [user, setUser] = useState(#{ name: "Alice", age: 30 }); const updateAge = () => { // 不可变更新:创建新Records setUser(#{ ...user, age: user.age + 1 }); }; return ( <div> <p>姓名:{user.name}</p> <p>年龄:{user.age}</p> <button onClick={updateAge}>年龄+1</button> </div> ); }; export default UserProfile; 示例 2:Tuples 作为固定长度状态 import React, { useState } from 'react'; const Scoreboard = () => { // 用Tuples存储分数(固定结构) const [scores, setScores] = useState(#[10, 20, 30]); const addScore = () => { // 不可变添加:创建新Tuples setScores(#[...scores, 40]); }; return ( <div> <p>分数:{scores.join(", ")}</p> <button onClick={addScore}>添加分数</button> </div> ); }; export default Scoreboard; 八、如何现在就体验 Tuples 与 Records? Tuples 与 Records 目前仍在开发中,但可以通过 Babel 或 TypeScript 的早期提案插件提前体验。 用 Babel 配置 安装插件: npm install @babel/plugin-proposal-record-and-tuple 2.配置 .babelrc: { "plugins": ["@babel/plugin-proposal-record-and-tuple"] } 九、总结 Tuples 与 Records 是 JavaScript 向"更可靠、更高效"进化的重要一步。它们通过原生支持深层不可变 和值语义,解决了传统数组/对象在状态管理中的痛点,同时无需依赖 Immutable.js 等第三方库。 无论是金融、游戏、数据分析还是前端框架开发,Tuples 与 Records 都能简化代码、减少 bug,并提升性能。现在就可以通过 Babel/TS 提前尝试,为未来的语言标准做好准备!

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册