
solidity는 컴파일 시 변수의 타입이 명시되어야 하는 정적 타입 언어이다.
지원되는 타입은 다음과 같이 존재한다.
고정 소수점은 아직 완벽하게 지원되지 않는다고 한다.
| Type | Values |
| bool | true/false |
| int8~256/uint8~256 | 8 bits to 256 bits Integer |
| int/uint | int256/uint256 |
| bytes1~32 | 1 bytes to 32 bytes byte |
| bytes | bytes32 |
| string | string |
다른 언어와 비교하여 solidity에서 사용하는 address라는 생소한 타입이 존재한다.
address는 20byte 크기를 가지며, 해당 주소의 잔고를 확인할 수 있는 balance나
송금을 할 수 있는 transfer 등 여러 멤버 함수를 가지고 있다.
키와 값의 쌍으로 이루어진 참조 유형이며
키는 매핑, 동적 배열, 컨트랙트, 열거형, 구조체를 제외한 내장 변수 타입 등 거의 모든 유형이 될 수 있다.
반면에 값은 어떤 타입이든 될 수 있다.
C++의 map, Python의 dictionary과 유사하지만 iterable 하진 않는다.
다른 언어에서 사용하는 구조체처럼 사용할 수 있다.
contract HelloWorld {
struct User {
string name;
uint age;
}
User[] users;
function setUser() public {
users.push(User("John Doe", 20));
}
function getUser(uint index) public view returns (User memory user) {
return users[index];
}
}
C와 같은 열거형 변수 타입이다.
마찬가지로 0 부터 시작한다.
contract HelloWorld {
enum Fruits { APPLE, BANANA, ORANGE }
function getFruits() public pure returns (Fruits) {
return Fruits.BANANA; // return 1
}
}
영구적으로 저장되는 상태 변수(State Variable), 함수 내에서만 존재하는 지역 변수(Local Variable)와
어디서든 사용이 가능한 전역 변수(Global Variable)가 존재한다.
다음과 같이 컨트랙트에서 선언한 상태 변수는 영구적으로 저장된다.
contract HelloWorld {
uint _myVariable1;
string _myVariable2;
}
함수 내에서만 사용할 수 있으며, 함수의 매개변수도 지역 변수이다.
함수 내에서 선언된 변수는 밖에서 접근할 수 없다.
contract HelloWorld {
function mySum(uint256 a) public pure returns (uint256) {
uint256 b = 4;
return a + b;
}
}
블록체인 및 트랜잭션을 접근할 수 있도록 어디서든 접근할 수 있는 변수 및 함수이다.
block 변수는 트랜잭션이 담기는 블록에 대한 정보이다.
msg는 함수를 호출한 주소 값을 얻을 수 있는 msg.sender, 송금하는 코인의 양이 저장된 msg.value 등 사용된다.
contract HelloWorld {
function currentBlockHash() public view returns (bytes32) {
// 현재 블록 번호
uint256 bNumber = block.number;
// 블록의 해시 값
bytes32 bHash = blockhash(bNumber);
return bHash;
}
function getBlockMiner() public view returns (address) {
// 블록 채굴자의 주소
return block.coinbase;
}
function getBlockTimestamp() public view returns (uint) {
// 블록의 timestamp 값
return block.timestamp;
}
function msgTest(address _address) public payable {
// _address한테 value만큼 송금
payable(_address).transfer(msg.value);
}
}
상태 변수 및 함수 등 정의된 범위에 따라 접근을 제어할 수 있다.
public으로 지정된 변수는 getter를 별도로 지정하지 않아도 자동으로 생성된다.
| 접근 제어자 | 내부에서 호출 | 외부에서 호출 | 상속된 컨트랙트에서 호출 |
|---|---|---|---|
| public | O | O | O |
| private | O | X | X |
| external | X | O | X |
| internal | O | X | O |
| 함수 타입 제어자 | 읽기 | 쓰기 | 가스 |
|---|---|---|---|
| view | O | X | X |
| pure | X | X | X |
| payable | O | O | O |
pure의 용도는 저장된 데이터를 읽고 쓸수 없지만,
함수 내 정의된 지역 변수나 인자로 받은 변수를 연산하는 등 결과를 반환하는데에 사용한다.
contract HelloWorld {
function mySum(uint256 a, uint256 b) public pure returns (uint256 result) {
return a + b;
}
}
함수의 오버로딩도 지원된다.
contract HelloWorld {
function sum(uint a) public pure returns (uint256) {
return a + 3;
}
function sum(uint a, uint b) public pure returns (uint256) {
return a + b + 3;
}
}
특정 함수를 실행시키기 전과 후에 특정 기능을 수행할 수 있도록 정의할 수 있다.
modifier 내 _를 기점으로 함수가 실행되기 전과 후의 기능을 수행한다.
다음의 예제에서 testFunction을 수행하면 decoded output이 6으로 찍히지만,
함수가 끝난 후 myVar getter를 호출하면 7이 된것을 확인할 수 있다.
contract HelloWorld {
uint public myVar = 5;
modifier testModifier {
myVar ++; // 함수가 실행되기 전 수행
_;
myVar ++; // 함수가 실행된 후 수행
}
function testFunction() public testModifier returns (uint256) {
return myVar;
}
}
컨트랙트의 소유주를 판별할 때 자주사용된다.
생성자를 이용하여 컨트랙트를 배포시 _owner에 배포자의 주소가 저장되며,
onlyOwner가 지정된 함수를 실행할 때
호출자가 배포자의 주소가 아니면 Error가 발생되는 원리이다.
contract HelloWorld {
uint public _myVar = 5;
address private immutable OWNER;
constructor() {
OWNER = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == OWNER, "Only Owner can call this.");
_;
}
function testFunction() public onlyOwner {
_myVar ++;
}
}
함수의 반환 값을 받을 수 없는 구조일 때, 로깅을 이용하여 데이터를 확인하는 방법을 쓰기도 한다.
이벤트를 발생 시 가스가 소비되니 무분별한 로깅은 자제한다.
contract HelloWorld {
uint public _myVar = 5;
event MyEvent(address indexed _from, uint _Var);
function testFunction() public {
_myVar ++;
emit MyEvent(msg.sender, _myVar);
}
}