작성
·
67
1
fn main() {
let mut s = String::from("헬로");
let r1 = &s;
let r2 = &s;
println!("r1 = {}, r2= {}", r1, r2);
}
여기서 println! 부분에 r1을 사용하건 &r1을 사용하건 둘다 "헬로" 로 같은 값이 나옵니다.
엄밀하게 말하면 r1은 문자열s의 주소값일 것 같아서 질문 드립니다.
그리고 주소값을 바탕으로 실제 값을 가져오는 건 일반적으로 &연산자가 아닌 *연산자를 사용하지 않는지요?
답변 1
0
fn main() {
let s = String::from("헬로");
let r1: &String = &s;
let r2: &&String = &r1;
let r3: &&&String = &&&s;
println!("r1 = {}, r2= {}, r3 = {}", r1, r2, r3);
}
수강 및 좋은 질문 감사합니다.
우선, println!("{}", v)
에서 어떤 값이 출력됐다고 해서, 그 값이 그대로 보인 게 아니라는 점을 명확히 하면 좋겠습니다.
질문에 적어주신대로, r1은 s의 주소값, 러스트 용어로 말하자면 참조값인 게 맞습니다. 둘의 타입이 명백히 다르죠. s
의 타입은 String
이고, r1
의 타입은 &String
입니다.
단지, println!
매크로에 활용되는 std::fmt::Display
트레이트 구현과 러스트의 deref 규칙 때문에 화면에는 "헬로"라는 문자열이 잘 보인 것 뿐입니다.
강의에 따로 다룬 내용이 아니므로 자세히 설명드리기는 어렵습니다만, 간단하게 적자면, println!에 {}자리에 찍을 대상들은 Display::fmt 메소드를 호출하게 되어있고, 참조값인 경우 원형(참조를 해제해서)의 fmt까지 쫓아가서 출력할 수 있는 기능이 있습니다.
따라서 몇 중으로 참조한 참조값이든 원래 타입의 값이 Display할 수 있는 값이라면 같은 내용이 화면에 보이는 것입니다.
질문에 적어주신, r1을 써야하느냐, &r1을 써야 하느냐는 질문에는, 상황에 따라 다를 수 있지만, 일반적으로 이미 r1이 참조값이므로, 그걸 또 참조할 일은 흔치는 않겠다고 말씀드리겠습니다. (하지만 C/C++같은 언어에서 때로 이중포인터를 쓰기도 하니, 비슷한 용례로 쓰일 수도 있겠죠)
더 궁금하신 내용이 있으시면 편히 말씀주세요