Ton与ETH的一些独特的区别
文章目录
- 前言
- 一、智能合约需要收取租金。
- 二、从数据到大数据的转变
- 三、智能合约不能运行其他合约的getter方法
- 四、合约不是无法改变的
- 五、Ton取消了无限制的数据结构
- 六、钱包和地址具有独立性
前言
TON区块链是一个现代化的区块链,它为智能合约开发带来了一些全新的理念。它是在以太坊推出后设计的,有机会学习EVM模型中哪些做得好,哪些可以改进。
如果你有智能合约的经验,你可能熟悉以太坊的Solidity语言和EVM。在学习TON开发时,你应该知道一些设计差异,这些差异使得TON的行为与你预期的不同。本文的目的是突出这些差异,并给你一些关于它们为何存在的想法。
TON的主要目标是将区块链带到全球每个人的手中,这意味着需要处理大规模的数据——每天数十亿用户发送数十亿笔交易。这可以看作是从数据到大数据的转变。当你需要存储一家餐厅的菜单时,SQL数据库是一个很好的选择,因为它可以运行强大且灵活的查询。但当你需要存储全球每个人的Facebook帖子时,SQL数据库可能就不是最佳选择了,这些大数据必须被积极地分片,这限制了你可以运行的查询的灵活性。
以下是TON区块链的六个独特方面,这些方面可能会让大多数Solidity开发者感到惊讶:
-
智能合约需要支付租金并向用户收费:以太坊的区块链费用模型类似于银行,发送交易需要支付交易费。但在TON中,智能合约需要为自己的资源成本付费,每个智能合约都持有TON代币余额,并用这个余额支付租金。如果智能合约的资金用尽,它最终将被删除。
-
智能合约之间的调用是异步且非原子的:在以太坊上,合约之间的调用是同步的,可以原子性地执行一系列操作。但在TON中,智能合约之间的通信是异步的,类似于微服务之间的通信,这使得维护一致性变得更加困难。
-
智能合约不能运行其他合约的getter方法:在以太坊上,一个合约可以直接读取另一个合约的状态。但在TON中,智能合约只能通过发送异步消息来通信,无法直接读取其他合约的数据。
-
智能合约代码不是不可变的,可以轻松修改:与以太坊上的智能合约代码一旦部署就不可更改不同,TON上的智能合约可以自由地修改自己的代码。
-
合约状态中不应该有无界的数据结构:在TON中,无界数据结构可能会导致垃圾信息攻击,因此建议避免在状态中使用无界数据结构。
-
钱包是合约,一个公钥可以部署多个钱包:在以太坊上,用户的钱包等同于他们的地址。但在TON上,钱包是必须部署的独立智能合约,用户可以部署多个钱包,每个钱包都有自己的地址。
这些设计差异使得TON在处理大规模用户和交易时更加灵活和可扩展。
-
智能合约需要支付租金并收取用户费用:
TON的智能合约需要为自己的存储空间支付租金,这类似于现实世界中的房产租赁。如果合约的余额不足以支付租金,它最终可能会被删除。这种费用模型鼓励开发者创建高效的合约,并为用户提供更好的服务。开发者可以选择自己支付TON代币来补贴用户,或者向用户收取费用以支付租金。 -
从数据到大数据的转变:
TON旨在处理大规模的数据和用户。这就像从使用SQL数据库存储餐厅菜单,转变为存储全球Facebook用户的帖子。在TON上,数据必须被分割(分片),这限制了可以运行的查询的灵活性,但更适合大规模数据处理。 -
异步消息传递:
在TON上,智能合约之间的通信是异步的,这意味着一个合约对另一个合约的调用会在未来的某个区块中被处理,而不是立即执行。这种设计增加了编程的复杂性,但提高了系统的可扩展性。 -
智能合约不能运行其他合约的getter方法:
与以太坊不同,TON上的智能合约不能直接调用其他合约的getter方法。这意味着合约无法立即获取其他合约的状态信息。getter方法只能被链下客户端调用,类似于以太坊钱包通过Infura这样的全节点来查询智能合约状态。 -
费用模型:
TON的费用模型与即时通讯应用(如Facebook Messenger)类似,而不是传统银行账户。在TON上,智能合约本身需要支付资源成本,包括存储和消息传递的费用。 -
智能合约的生命周期管理:
TON上的智能合约需要管理自己的生命周期,包括支付租金和处理用户费用。这要求开发者在设计合约时考虑更多的经济因素。
TON的这些特点使其成为一个高度可扩展且适合大规模应用的区块链平台。然而,这些设计决策也意味着开发者需要适应新的编程模型和最佳实践。随着TON生态系统的发展,我们可以期待看到更多创新的去中心化应用和服务的出现。
一、智能合约需要收取租金。
在TON区块链上,智能合约需要为其存储空间支付租金,这是一种独特的费用模型。与以太坊不同,TON的智能合约不仅要在部署时支付一次性费用,还需要定期支付租金以保持其数据在区块链上的状态。这种模型鼓励开发者创建高效的合约,并为用户提供更好的服务。
例如,假设你开发了一个去中心化的应用程序(DApp),它需要存储用户的数据。在TON上,你的智能合约将持有TON代币余额,并使用这个余额来支付租金。如果智能合约的资金耗尽,它最终可能会被删除,但所有数据都是可恢复的。这种费用结构意味着,如果你只在短时间内持有数据,你将支付较少的费用。这与矿工的成本更加一致,因此更容易扩展。
开发者有很大的自由度来选择如何资助其合约的操作。开发者可以自掏腰包用TON代币资助合约,从而补贴用户;或者,他们可以对用户执行的不同操作收取费用,并将这些费用保留在合约余额中,用于未来的租金支付。这种模式类似于Facebook Inc(或Meta Inc)在Facebook Messenger上发送消息的成本由公司承担,而不是由发送消息的用户承担。
这种设计使得TON区块链非常适合大规模应用,因为它考虑到了数据存储和处理的长期成本,并通过持续的费用模型来确保网络的可持续性。开发者需要在设计智能合约时考虑到这一点,并实现相应的逻辑来管理资金和支付租金。这种模式也意味着用户在使用DApp时可能会遇到不同的费用结构,因为这些费用可能会被转嫁到他们身上。
二、从数据到大数据的转变
在以太坊上,智能合约之间的调用是同步且具有原子性的,这是构建强大去中心化金融(DeFi)生态系统的关键因素之一。在单笔交易中,你可以将一些WBTC作为抵押品提供给Compound的合约,然后借用USDC,再将这些USDC与Uniswap的合约交易以换取更多的WBTC,从而增加你的WBTC头寸。整个过程甚至是原子性的——如果这些步骤中的任何一个失败,即使是最后一个,整个交易就会像从未发生过一样回滚。
当你的智能合约调用另一个智能合约的方法时,该调用会在同一笔交易中立即处理。在这方面,以太坊非常类似于在单一服务器上运行整个后端。你的后端的每个部分都能够同步访问任何其他部分——这是一种非常容易理解的方法。但它有一个缺点,它只能增长到适合在一个地方为止。
将单一服务器转移到微服务集群
如果你将以太坊想象成运行在单一服务器上的单体应用程序,TON则更像是一组微服务。想象一下,每个智能合约可能在不同的机器上运行。如果两个智能合约想要相互调用,就像两个微服务通过网络通信一样,它们可以通过网络发送消息。这个消息需要一些时间来传递,因此通信突然变得异步了!这意味着当你的智能合约调用另一个智能合约的方法时,这个调用将在交易终止后,在某个不同的未来区块中被处理。
这种情况更难以理解。如果消息发送和接收之间的条件发生了变化,会发生什么?例如,调用合约的余额在发送消息时是一个值,但等到第二个合约处理这个调用时,余额已经改变了。保持一致性变得更加困难,可能会出现错误。那么原子性呢?如果你链接了三个调用,但只有最后一个失败了怎么办?如果你需要回滚所有的更改,你将不得不手动进行。
举例说明:
假设在TON区块链上,我们有两个智能合约:ContractA
和 ContractB
。
ContractA
想要调用ContractB
的一个方法,并且传递一些TON币作为支付。ContractA
发送了一个消息给ContractB
,包含了调用的方法和支付的TON币。- 由于通信是异步的,
ContractB
可能在几个区块之后才收到这个消息。 - 在等待
ContractB
处理期间,ContractA
的余额可能已经因为其他交易而发生了变化。 - 当
ContractB
尝试处理这个调用时,它可能会发现ContractA
的余额不再足够支付之前承诺的金额。 - 如果
ContractB
依赖于ContractA
的余额来执行某些操作(比如释放代币或执行某些逻辑),那么这个操作可能会失败,因为它依赖的状态已经改变。 - 如果需要回滚这个操作,
ContractB
必须实现额外的逻辑来检测这种情况并执行回滚,这可能涉及到手动干预或复杂的错误处理逻辑。
在这种情况下,开发者需要在设计智能合约时考虑到异步通信的复杂性,并实现额外的逻辑来确保操作的原子性和一致性。这可能包括使用事务管理器、状态通道或其他机制来确保跨合约调用的一致性和正确性。
三、智能合约不能运行其他合约的getter方法
在TON区块链上,智能合约不能调用其他合约的getter方法,这是与以太坊同步调用不同智能合约特性的另一个方面。在以太坊上,合约之间的调用是同步的,从一个不同的智能合约读取数据是直接的。比如说,我的合约有USDC的余额。由于USDC本身也是一个合约,为了知道它自己的余额,我的合约将不得不调用USDC合约的getBalance
方法。
回想一下在单一服务器上运行的单体应用?这种方法的一个巨大好处是每个服务都可以直接读取每个其他服务的状态内存。
当我们在不同机器上运行独立的微服务时,跨服务读取状态内存突然变得不可能。TON上的智能合约只能通过发送异步消息来通信。如果你需要从另一个合约查询数据,并且你需要立即得到答案,那你就不走运了。
情况实际上变得更加奇怪。如果你在TON智能合约上看到getter方法,比如getBalance
——这些方法不能从其他智能合约中访问。Getter方法只能被链下客户端调用,类似于你的以太坊钱包可以使用像Infura这样的全节点来查询任何智能合约的状态。
举例说明:
假设在以太坊上,你有一个名为MyToken
的代币合约,它有一个balanceOf(address _owner)
的getter方法,可以查询任何账户的余额。如果你在以太坊上有一个名为MyContract
的合约,它想要获取一个账户在MyToken
合约中的余额,它可以直接调用MyToken(balanceOf: address _owner)
方法来获取这个信息。
在TON上,情况就不同了。假设你有两个TON智能合约,ContractA
和ContractB
。ContractB
有一个getBalance
方法,可以返回与合约相关联的余额。如果ContractA
想要获取自己的ContractB
余额,它不能直接调用ContractB.getBalance()
。相反,ContractA
需要发送一个消息给ContractB
并等待异步响应。这个响应可能需要几个区块的时间,并且ContractA
不能保证在它需要的时候立即得到这个信息。
因此,TON上的智能合约开发者必须考虑到这种异步通信的复杂性,并可能需要实现额外的逻辑来处理状态的不确定性和延迟。这可能包括使用事件、日志记录或其他机制来跟踪和验证跨合约调用的结果。
四、合约不是无法改变的
在以太坊上,智能合约的代码是不可变的,这一点最初是受到律师起草的法律文件的启发——因此被称为“智能合约”。开发者将法律合同的条款编写成代码,而代码,正如你所知,就是法律。当现实世界中的双方签订合同时,合同是不可变的。如果任何一方想要改变合同条款,他们会起草一份新的合同。
多年来,开发者社区已经学会了克服这一限制,并生成了一些繁琐的模式,这些模式依赖于一些技巧,比如使用代理合约指向不同的合约,以实现升级。
与律师不同,软件工程师被教导说,每段代码都有错误。即使错误永远不会发生,需求仍然会随着时间的推移而变化,代码也必须经常升级和修改。
在TON中,合约应该是不可变的借口被完全抛弃了。智能合约可以自由地修改自己的代码,就像编写任何其他状态变量一样。如果合约写入代码变量,那么它是可变的,如果没有,那么它是不可变的。这在实践中并不是一个大的变化,它只是使繁琐的代理模式变得多余。
举例说明:
假设在以太坊上,你有一个名为LendingContract
的智能合约,它实现了一个借贷平台的逻辑。随着时间的推移,你发现了合约中的一些漏洞,或者你想添加一些新功能。在以太坊上,你不能直接修改LendingContract
的代码,而是需要部署一个新的合约,比如LendingContractV2
,然后让用户迁移到新合约。
在TON上,你可以简单地修改现有的LendingContract
合约。例如,你可以编写一个新的升级函数upgradeContract
,这个函数可以更改合约的状态或逻辑。如果合约需要更新其代码,它可以调用这个函数来实现自我升级,而不需要部署一个新的合约。
// 这是一个简化的TON智能合约示例,展示了如何实现自我升级
contract LendingContract {var code : Cell; // 存储新代码的变量// 升级合约的函数function upgradeContract(newCode : Cell) {self.code = newCode;// 实现升级逻辑,可能包括调用内置函数来更新合约代码}// 其他合约逻辑...
}// 假设这是新版本的代码
Cell newCode = ...;// 调用升级函数来更新合约
LendingContract.upgradeContract(newCode);
在这个例子中,LendingContract
合约有一个upgradeContract
函数,它允许合约自我更新其代码。这种方式简化了合约升级的过程,因为开发者不需要部署新的合约,用户也不需要迁移到新合约。这种灵活性使得TON上的智能合约更加适应不断变化的需求和市场条件。
五、Ton取消了无限制的数据结构
在TON区块链中,智能合约的状态中不应该有无界的数据结构,这是因为无界数据结构可以无限增长,可能会导致一些问题。例如,如果一个攻击者试图通过不断添加更多的条目来滥用合约,他们可能会发动拒绝服务(DoS)攻击,从而阻止其他用户使用该合约。在以太坊上,智能合约开发者不需要太担心这个问题,因为以太坊的费用模型规定写入新状态数据的用户需要支付费用,这使得垃圾信息攻击在经济上不可行。然而,在TON中,情况就不同了。
TON的“Bag of Cells”架构要求开发者维护由1023位块(称为“cells”)组成的合约状态。映射是作为单元树实现的,写入树的叶子需要沿着整个树的高度写入新的哈希。如果攻击者在映射中垃圾信息攻击键,一些用户余额可能会被推到树的深处,以至于更新它们会超过gas限制。因此,TON的最佳实践是避免在状态中使用无界数据结构,以保护合约免受DoS漏洞的攻击。如果需要处理可能无限增长的数据,如USDC合约中的用户余额,应该将单个合约拆分为多个子合约,每个子合约保存单个用户的余额。这种方法可以避免无界数据结构带来的问题,并保持合约的可扩展性和安全性。
例如,如果一个USDC代币合约需要维护每个用户地址的余额映射,而不是在单个合约中无限增长这个映射,开发者应该创建多个子合约,每个子合约只处理一个用户的余额。这样,即使某个子合约受到攻击或垃圾信息攻击,也不会影响到整个系统的稳定性。这种设计方法在TON上是推荐的,因为它有助于避免由于无界数据结构导致的潜在问题。
六、钱包和地址具有独立性
在以太坊上,用户的钱包等同于他们的地址,地址直接由公钥(及其对应的私钥)派生。这是一个一对一的关系,一个公钥对应一个地址,一个地址对应一个公钥。只要用户知道他们的私钥,他们就永远不会丢失他们的钱包。
此外,在以太坊上,用户无需采取任何特殊措施就可以拥有钱包。以太坊地址就是钱包。地址可以持有原生货币ETH,地址可以持有ERC20代币和NFT,地址可以直接向其他智能合约发送和签署交易。
从地址到合约
在TON上,钱包不是隐含的,它们是必须像任何其他智能合约一样部署的独立智能合约。当新用户想要开始使用TON区块链时,他们的第一步将是在链上部署一个钱包。这个钱包的地址是从钱包合约代码和各种初始化参数(如用户的公钥)派生的。
这意味着用户可以部署多个钱包,每个钱包都有自己的地址。这些钱包可以在它们的代码上有所不同(基金会不时发布不同的官方代码版本)或者在它们的初始化参数上有所不同(其中一个参数通常是序列号)。这也意味着即使用户知道他们的私钥,他们仍然必须刻意记住他们的钱包地址(或用于构建的初始化参数)。
向TON上的某个dapp发送交易涉及使用用户的私钥签署消息。与以太坊不同,这个交易不是发送到dapp智能合约,而是发送到用户的钱包合约,后者将转发消息到dapp智能合约。
这种设计方法为TON开辟了一个新的灵活维度。社区随着时间可以发明新的钱包合约,例如考虑一个没有nonce(交易序列号)的钱包,允许从不同客户端并行发送多个交易而无需事先同步。此外,特殊钱包如多重签名钱包(即使在以太坊上也需要部署特殊智能合约),表现就像它们的常规对应物一样。
举例说明:
假设用户Alice想要在TON区块链上部署一个新的钱包。她首先选择一个钱包合约的代码,这可能是TON基金会提供的官方版本,也可能是社区开发的一个新版本。Alice还需要提供一些初始化参数,比如她的公钥和一个序列号。
- Alice使用她的私钥对初始化参数进行签名,生成一个部署交易。
- 她将这个交易发送到TON网络,网络中的节点验证交易并将其打包进一个区块。
- 一旦交易被确认,Alice的新钱包合约就被部署在链上,并且她获得了一个新的钱包地址。
- Alice可以使用这个钱包地址来接收和发送资金,以及与TON上的其他智能合约进行交互。
如果Alice想要部署另一个钱包,她可以重复这个过程,使用不同的初始化参数或不同的钱包合约代码。这样,她就可以拥有多个钱包,每个钱包都有自己的地址和功能。
这种模式提供了极大的灵活性,但也要求用户更加注意管理他们的钱包地址和相关的初始化参数。同时,这也为创新的钱包解决方案提供了空间,比如可以实现更复杂的资产管理和交易功能的特殊钱包合约。
相关文章:

Ton与ETH的一些独特的区别
文章目录 前言一、智能合约需要收取租金。二、从数据到大数据的转变三、智能合约不能运行其他合约的getter方法四、合约不是无法改变的五、Ton取消了无限制的数据结构六、钱包和地址具有独立性 前言 TON区块链是一个现代化的区块链,它为智能合约开发带来了一些全新…...

C++ | Leetcode C++题解之第396题旋转图像
题目: 题解: class Solution { public:int maxRotateFunction(vector<int>& nums) {int f 0, n nums.size();int numSum accumulate(nums.begin(), nums.end(), 0);for (int i 0; i < n; i) {f i * nums[i];}int res f;for (int i …...

前向渲染路径
1、前向渲染路径处理光照的方式 前向渲染路径中会将光源分为以下3种处理方式: 逐像素处理(需要高等质量处理的光)逐顶点处理(需要中等质量处理的光)球谐函数(SH)处理(需要低等质量…...

Python画笔案例-040 绘制五角星顶圆
1、绘制五角星顶圆 通过 python 的turtle 库绘制五角星顶圆,如下图: 2、实现代码 绘制五角星顶圆,以下为实现代码: """五角星顶圆.py """ import turtledef draw_circle(d):turtle.left(90)for _ …...

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例
伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教…...

期货量化-群体优化算法:混合蛙跳算法(SFL)
1. 概述 混合蛙跳算法(Shuffled Frog Leaping Algorithm, SFL)由 M. Eusuff 等人在2003年提出。这一算法结合了模因算法与粒子群优化算法的原理,灵感来源于一群青蛙在觅食过程中的行为模式。 SFL 最初作为一种求解组合优化问题的元启发式方法…...

tensorflow-线性回归python入门
目录 读入库 构造数据 建立训练和测试数据 创建第一层到最后一层的神经网络 开始测试 sin函数回归 读入库 import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import time 构造数据 X np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, …...

VSCode学习笔记
1. 快捷键 KeyDescriptionPlatformF1打开命令面板(Command Palette)Win10Shift Delete剪切当前光标所在的代码行Win10 2. 文件 2.1 在文件列表中定位当前文件 操作路径:右键单击文件名 ⇒ 在右键菜单中点击 【Reveal in Explorer View】...

【Canvas与艺术】菊花孔雀螺旋
【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>菊花孔雀螺旋</title><style type"text/css">…...

circuitjs 普通开关和按钮开关
circuitjs 各类开关中最基本的有 (普通)开关 和 按钮开关(瞬时开关). 添加 在菜单 “绘制–无源元件–添加开关” 下可以添加一个普通开关.在菜单 “绘制–无源元件–添加按钮开关” 下可以添加一个按钮开关. 两者在缺省外观上没有什么区别, 如上, 左边是普通开关, 右边是按钮…...

客户端绑定本地端口与服务器建立连接的详细实现
客户端绑定本地端口与服务器建立连接的详细实现 一、网络编程基础1.1 TCP/IP协议1.2 套接字(Socket)1.3 客户端与服务器模型二、客户端程序的设计2.1 需求分析2.2 流程设计三、具体代码实现3.1 伪代码3.2 C代码实现四、代码详解4.1 初始化套接字库4.2 创建套接字4.3 绑定本地…...

C++ std::bind函数用法
看一个例子解释用法: TcpServer类的构造函数中定义: acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this,std::placeholders::_1, std::placeholders::_2));// 有一个新的客户端的连接,acceptor会执行这…...

Caffenie配合Redis做两级缓存
一、什么是两级缓存 在项目中。一级缓存用Caffeine,二级缓存用Redis,查询数据时首先查本地的Caffeine缓存,没有命中再通过网络去访问Redis缓存,还是没有命中再查数据库。具体流程如下 二、简单的二级缓存实现-v1 目录结构 2…...

MATLAB实现PID参数自动整定
目录 1、项目说明 2、文件说明 1、项目说明 本项目旨在通过 MATLAB 语言实现 PID 参数的自动整定,并设计了一个直观易用的 GUI 界面。该系统特别适用于实验室环境下的 PID 参数自整定任务。整定的核心原则在于优化系统性能,使系统的衰减比尽可能接近理…...

UE5学习笔记21-武器的射击功能
一、创建C类 创建武器子弹的类,创建生产武器子弹的类,创建弹壳的类,生产武器子弹的类的父类是武器的类 创建后如图,ProjectileMyWeapon类(产生子弹的类)继承自weapon类,Projectile(子弹的类),Casing(弹壳声…...

Mamba模型学习笔记
笔记来源:bilibili Transformer 的死穴 Transformer 结构的核心是自注意力机制层,无论是 encoder 还是 decoder,序列数据都先经过位置编码后喂给这个模块。 但是自注意力机制的计算范围仅限于窗口内,而无法直接处理窗口外的元素…...

android kotlin 基础复习 继承 inherit
1、新建文件kt 2、代码: /**用户基类**/ open class Person1(name:String){/**次级构造函数**/constructor(name:String,age:Int):this(name){//初始化println("-------基类次级构造函数---------")println("name:${name},age:${age}")} }/**子…...

读软件设计的要素06概念完整性
1. 概念完整性 1.1. 当概念组合成一个软件时,它们可以同步以便协调行为 1.1.1. 同步可能会消除一个概念的某些行为,但决不会添加与该概念的规范不一致的新行为 1.1.2. 在使用概念设计软件时,即使你没有精确定义同步,至少要说服自…...

Java 每日一刊(第2期):搭建开发环境
文章目录 JVM、JRE、JDKJVM(Java Virtual Machine,Java 虚拟机)JRE(Java Runtime Environment,Java 运行时环境)JDK(Java Development Kit,Java 开发工具包)JVM、JRE、JD…...

探索EasyCVR与AI技术深度融合:视频汇聚平台的新增长点
随着5G、AI、边缘计算、物联网(IoT)、云计算等技术的快速发展,万物互联已经从概念逐渐转变为现实,AIoT(物联网人工智能)的新时代正在加速到来。在这一背景下,视频技术作为信息传输和交互的重要手…...

IBM中国研发部调整:全球化与本土化的新平衡
如何看待IBM中国研发部裁员? 近日,IBM中国宣布撤出在华两大研发中心,引发了IT行业对于跨国公司在华研发战略的广泛讨论。这一决定不仅影响了众多IT从业者的职业发展,也让人思考全球化背景下中国IT产业的竞争力和未来发展方向。面对…...

C++入门基础篇
引言 说到编程语言常常听到的就是C语言C Java 。C语言是面向过程的,C是和Java是面向对象的,那么什么是面向对象呢?什么又是面向过程呢?C是什么?封装、继承、多态是什么?且听我絮絮叨叨。 C入门基础 1.命名…...

Qt QListWidget 代码范例,以及Qt 天坑:setStyleSheet失效问题
一、坑之所在 1.写了StyleSheet的QString并进行了设置 this->setStyleSheet(styleSheet_M);2.注释后,将StyleSheet换到UI form里去,然后又手动清理了UI form里的StyleSheet 重新使用代码设置,此时代码设置失效了 二、根本解决 1.手动从…...

Unity AnimationClip详解(1)
【动画片段】 前文我们介绍了骨骼动画,在Unity中骨骼动画的部分静态数据存储在SkinedMeshRender中,而另一部分动态的关键帧数据就是存储在AnimationClip中的。 关键帧数据来自与FBX、OBJ等动画模型文件,可以在动画导入后的Animation选项卡中…...

在这12种场景下会使Spring事务失效--注意防范
在某些业务场景下,如果一个请求中,需要同事写入多张表的数据,但为了保证操作的原子性(要么同事插入数据成功,要么同事插入失败),例如,当我们创建用户的时候,往往会给用户…...

SOPC:Nios II Processor -> Vectors
Reset Vector——复位向量 Exception Vector——执行向量 两个向量地址都存储着程序 1.Reset Vector 当FPGA进行复位时,FPGA就重新开始执行程序,这时就需要从EPCS中读取程序。由于FPGA的程序存放在EPC…...

golang学习笔记11——Go 语言的并发与同步实现详解
推荐学习文档 基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总golang学习笔记01——基本数据类型golang学习笔记02——gin框架及基本原理golang学习笔记03——gin框架的核心数据结构golang学习笔记04——如何真正写好Golang代码&…...

关于汽车加油是加200还是加满的思考
车子快开了1万公里了,每个月保险会送一个200-15的加油优惠券,所以之前一直是每次加200的习惯, 最近突然觉得经常去加油很麻烦,而且很浪费时间, 需要重新评估一下, 一次加200 or 一次加300 or 一次加满&am…...

C# 去掉字符串最后一个字符的5种方法
C# 去掉字符串最后一个字符的 5 种方法 (1)Substring string original "Hello!"; string result original.Substring(0, original.Length - 1); Console.WriteLine(result); // 输出: Hello (2)Remove string o…...

[Redis] Redis中的String类型
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...