value type
의 변수들은 단일 메모리 공간인 EVM stack
에 저장된다.
함수의 인자로 사용되는 경우, 값을 복사해서 전달한다.
따라서 함수 내에서 값을 아무리 바꿔도 원래 변수의 값은 변하지 않는다.
논리식은 반드시
true
또는false
로 표현돼야 한다.
주의!! 0 또는 1로 정의할 수 없다!
연산자
!
: 논리적 부정&&
: AND||
: OR==
: 같다!=
: 다르다
부호
- int : 부호 있음, -128~127
- uint : 부호 없음, 0~255
비트
int8
,int16
,int32
,int64
,int256
(==int
)uint8
,uint16
,uint32
,uint64
,uint256
(==uint
)
좌변의 타입 크기가 우변의 타입 크기보다 크면 타입이 달라도 같이 사용이 가능하다.
그러나 우변의 타입 크기가 더 크다면 같이 사용할 수 없다.
연산자
- 비교 :
<=
,<
,==
,!=
,>=
,>
- 비트 연산 :
&
,|
,^
(XOR),~
(부정)- 시프트 연산 :
<<
,>>
- 사칙 연산 :
+
,-
,/
,%
(나머지),**
(제곱)
1~32bytes 크기로 고정 크기의 바이트 배열을 선언할 수 있다.
bytes1
(==bytes
),bytes2
, ...,bytes32
1바이트의 배열을 사용할 경우,bytes1
보다bytes
를 사용하는 것이 낫다.
(padding rules
에 의해bytes1
가 실제로 1바이트만 사용하지만 32바이트를 차지함)
연산자
- 비교 :
<=
,<
,==
,!=
,>=
,>
- 비트 연산 :
&
,|
,^
(XOR),~
(부정)- 시프트 연산 :
<<
,>>
- 인덱스 접근 : 예를 들어
x
가bytes32
인 경우,x[k]
(0<=k<32)로 각 바이트를 출력할 수 있다.
[참고]
Dynamically-size byte arrays
(동적 바이트 배열은 Value-type이 아님!)
bytes
: 동적으로 크기를 갖는 바이트 배열string
: 동적으로 크기를 갖는 UTF-8 인코딩된 문자열
0x
로 시작하는 최대 40자리 16진수 문자열 (크기: 20바이트)sha3
해시 함수를 통해 생성된다.- 알파벳 대소문자를 구분한다.
address
타입에 제공되는 함수들
함수명 설명 balance()
해당 주소의 잔액 (Wei 단위) transfer()
- 지정된 양의 Ether
를 주소로 전송하는 함수 (Wei 단위)
- 전송 실패시 자동으로 이전 상태로 되돌린다.
- 소모 가스 : 2300 gas, 조정 불가send()
- Ether
를 보내는 함수
- 전송 실패시false
값만 반환할 뿐, 자동으로 지불이 취소되지 않는다. (직접revert
를 해줘야함)
- 소모 가스 : 2300 gas, 조정 불가call()
- success condition과 return data를 반환한다.
- 소모 가스 : 조정 가능, 제한 없음
send() 사용시 주의점
호출 스택의 depth가 1024면 전송이 실패하는데 호출한 사람이 이를 의도할 수 있다.
또한, 가스가 소진되면 전송이 실패하기 때문에 안정적인 전송이 어렵다.
send()
를 사용하려면 리턴값을 항상 확인하고revert()
를 넣어주자.
그래도 웬만하면transfer()
와 같이 더 좋은 함수를 사용하는 것이 낫다.call() 사용시 주의점
다른 컨트랙트 함수를 실행할 때 형식 검사, 함수 존재 검사, 인수 패킹을 우회하므로call()
은 사용하지 않는 것이 좋다.
유한한 상수값을 이용해서 사용자 지정 형식을 만든다.
아래 예시를 보면, Low, Medium, High 순서로 0, 1, 2의 값이 부여된다.
enum InvestmentLevel {Low, Medium, High}
InvestmentLevel level = InvestmentLevel.Medium; // level = 1
reference type
의 변수는 그 값이 저장된 주소를 통해 접근한다.
이런 변수들은 세가지 타입의 데이터 영역에 저장할 수 있다.
memory
: 값을 영구적으로 보존되지 않고 메모리에서만 존재한다.storage
:state 변수
처럼 블록체인에 영구적으로 저장한다.calldata
: 오직external
함수의 파라미터에서만 사용할 수 있다. 수정이 불가능하고 영구 보존이 되지않는 영역으로memory
와 비슷하게 동작한다.
Case Data location Local variable Memory or Storage State variable Only Storage Parameter of internal function Memory or Storage or Calldata
선언시 배열의 크기를 지정한다.
선언 후 값 할당하는 방법
function f() {
int32[5] memory fixedArray;
fixedArray[0] = 5;
}
인라인으로 할당하는 방법
function f() {
int32[5] memory fixedArray = [int32(5), 9, 1, 3, 4];
}
선언시 배열의 크기를 지정할 필요가 없다.
항목을 추가하려면 push()
를 사용한다.
// 배열에 항목 추가
dynamicArray.push(2);
데이터 영역에 따라 크기 조정 방식이 다르다.
storage
일때
function f() {
int32[] dynamicArray; // 암시적으로 스토리지 영역 사용
dynamicArray.length = 5; // 배열 길이 재설정
}
memory
일때
function f() {
int32[] memory dynamicArray; // 명시적으로 메모리 영역 사용
...
dynamicArray = new int32[](5); // 새로 생성해서 크기 조정
}
bytes
와 동일하지만 length
와 push()
멤버가 없다.
string name = "SOKURI";
struct
는 서로 다른 데이터 타입의 항목을 포함하는 집합 타입으로, 사용자 정의 타입이다.
// 구조체 정의
struct Candidate {
address account;
string description;
}
// 구조체 초기화
function addCandidate(address candidateAddress, string candidateDescription) {
Candidate memory candidate = Candidate({account:candidateAddress, description:candidateDescription});
}
스토리지 데이터 영역에서만 사용할 수 있다.
상태변수 또는 스토리지 참조형으로만 선언할 수 있다.
해시 테이블로 키에 대응하는 값을 저장한다.
key
와 value
의 유형을 반드시 선언해야 한다.
mapping(address => int) public coinBalance;