불변의 주위에 내 머리를 얻기


13

나는 객체 지향 프로그래밍에 익숙하지 않으며, 이해하는 데 시간이 걸리는 한 가지 개념은 불변성입니다. 어젯밤에 전구가 꺼 졌다고 생각하지만 확인하고 싶습니다.

불변의 객체를 변경할 수 없다는 진술을 보았을 때, 예를 들어 다음을 수행 할 수 있기 때문에 당황합니다.

NSString *myName = @"Bob";
myName = @"Mike";

여기서 방금 변경 불가능한 유형 NSString의 myName을 변경했습니다. 내 문제는 "object"라는 단어가 메모리의 물리적 객체 또는 추상화 "myName"을 나타낼 수 있다는 것입니다. 전자의 정의는 불변성의 개념에 적용됩니다.

변수에 관해서는, 불변성의 더 명확한 (나에게) 불변의 객체 의 은 메모리에서의 위치, 즉 참조 (포인터라고도 함)를 변경해야만 변경할 수 있다는 것입니다.

이것이 맞습니까, 아니면 여전히 숲에서 길을 잃었습니까?


13
귀하의 유형이 (이)가 아닌 NSString" 포인터NSString"이며 변경할 수 없습니다. 나는 객관적인 C의 아무것도 몰라,하지만 난 당신의 예제에 같은데요 @"Mike"의 새로운 인스턴스를 만드는 NSString과에 할당 포인터 , myName. 따라서 myName가리키고 있는 객체를 가리 키지 않고 그대로 가리키고 있습니다.
fwgx 2016 년

2
@fwgx 답을 넣으면 공감할 수 있습니다.
Gulshan

모든 답장을 보내 주셔서 감사합니다. 매우 도움이됩니다. 나는 불변의 객체가 그것을 가리키는 변수가 아니라 메모리의 값이라는 것을 이해한다.
Michael Mangold

완료 @Gulshan, ... 아래 참조
fwgx

불변성을 이해하기 위해 바인딩 (예 : 객체에 이름 제공)과 가변성을 명확하게 구분하는 프로그래밍 언어 (예 : 다른 객체에 이름을 다시 할당 할 수있는 프로그래밍 언어)를 배우는 것이 좋습니다. ML (SML, Ocaml, F #)은 좋은 예입니다.
질 'SO-정지 존재 악마'

답변:


4

당신이 올바른 방향으로 가고있는 것처럼 들리지만 아직 그것을 얻지 못했습니다. 이것은 틀렸다 :

여기서 방금 변경 불가능한 유형 NSString의 myName을 변경했습니다. 내 문제는 "object"라는 단어가 메모리의 물리적 객체 또는 추상화 "myName"을 나타낼 수 있다는 것입니다.

당신의 코드에서, myName하지 불변의 유형이다 NSString그것은이다, 가변 타입 NSString*(있는 NSString 포인터). 당신이 놓친 중요한 것은 이해하는 것 같은데 포인터가 또 다른 값는 완전히 분리가 가리키는 것은에서 생명이있다 (당신의 수명을 통해 그것을 부분의 방법을 변경하는 경우, 또는 일을).

당신은 말한다 :

... 불변 객체의 값은 메모리에서의 위치, 즉 참조 (포인터라고도 함)를 변경해야만 변경할 수 있습니다.

이것은 잘못이다. 객체는 그것을 가리키는 포인터를 소유 하지 않으며 객체의 메모리 위치가 포인터에 의해 제어 되거나 영향을받지 않습니다.

따라서 NSString예제 ( @"Bob"@"Mike") 의 두 객체 는 myName변수 와 완전히 별개입니다 . 또한 서로 완전히 분리되어 있습니다. 변경하는 경우 myName에 지점 @"Mike"을 가리키는 대신 @"Bob", 당신은 변화하지 않는 NSString개체를.


완성도를 높이기 위해 가비지 컬렉터가 포인터를 변경 하면 대상 객체에 영향을 줄 있다는 점에서 더 복잡해 집니다. 그러나 이것은 구현 세부 사항으로 코드의 관찰 가능한 동작에 영향을 미치지 않아야합니다.


17

당신은 말을 잃었습니다. 불변성 의미 : 변수를 변경하지 않는 한 변수는 다른 변수로 무엇을 하든지 항상 같은 값을 "포함"합니다.

C의 예제 (이를 허용하는 아키텍처를 가정하면 약간 단순화 됨) :

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

이제는 더 이상 문자열 "Hello World"를 "포함"(즉, 가리킴)하지 않지만 대신 "Yello World"입니다.

Java 및 (EDIT : safe) C #과 같이 문자열을 변경할 수없는 언어에서는 그렇게 할 수 없습니다. 절대 안돼. 이것은 프로그램의 모든 부분이 문자열에 대한 참조를 안전하게 유지하고 그 내용이 절대로 변하지 않는다는 것을 의미합니다. 그렇지 않으면, 그들은 단지 안전한면에 있도록 사본을 만들어야 할 것입니다.

그러나 변수는 여전히 변경 가능합니다. 다른 객체를 가리킬 수 있습니다. 단지 객체 자체가 등 뒤에서 바뀌지 않는다는 것입니다.


1
기술적 으로 C #에서 문자열 내용을 수정할 수 있습니다unsafe . 코드 만 사용하면 됩니다.
Aaronaught

1
Aaronaught : 정보 주셔서 감사합니다. 당신 말이 맞습니다. : 방법을 알 필요가 모든 사람들을위한 msdn.microsoft.com/en-us/library/ms228599.aspx
user281377

10

변수를 객체와 혼동하고 있습니다. 변수는 객체에 대한 참조를 저장하는 데 사용될 수 있지만 객체는 아닙니다. 변수가 아닌 변경할 수없는 객체이므로 변수를 한 객체에서 다른 객체로 변경할 수 있지만 변경할 수없는 경우 객체의 속성을 변경할 수 없습니다.

시끄러운 술취한 이웃으로 물건을 생각하십시오. 그가 합리적 (변동 가능)이라면 문을 두드리고 소음을 많이 내지 않는 생활 방식으로 바꿀 수 있습니다. 그러나 그가 변하지 않는다면, 당신의 유일한 변화는 다른 누군가가 들어 오기를 희망하는 것입니다!


3
나는 음소거하고 싶었던 이웃을 가졌습니다.
Dave Nay

나는 당신의 설명이 충분하기 때문에 두 번째 단락에서 당신의 모범이 필요하다고 생각하지 않습니다. IMO 예제는 혼란 스러울 수 있습니다. 그러나 챕터의 질문에 간결한 대답은 +1입니다.
Paul McCabe

@DaveNay : 스텔스 펑에 대해 사과드립니다. 전혀 의도되지 않았습니다.
Kilian Foth

6

변수는 객체가 아닙니다. 변수는 이름으로, 객체 (보다 일반적으로 값)를 나타냅니다.

예를 들어 "골키퍼"는 목표를 방어 할 책임이있는 개체 (사람)를 나타내는 데 사용하는 이름입니다. 그러나 만약 내가 그 사람을 다른 사람으로 대체한다면 (전자가 다치거나 그렇지 않기 때문에), 새로운 사람은 이제 "골키퍼"라고 불립니다.

대 입문은 변수를 변경 가능하게 만드는 것입니다 (Haskell과 같은 일부 언어에는 변수가 없으며 실제로는 불변 변수를 사용합니다). 이름의 의미를 재정 의하여 값을 다시 지정할 수 있습니다.

이제 객체 자체 변경할 수 없습니다. 수천 년 전에 다이아몬드는 불변이라고 생각했을 수 있습니다. 다이아몬드로 무엇을 하든지 수정하지 못했습니다. 당신이 그것을 waggawooga ( "우리 부족의 가장 큰 반짝이는 돌"로 약하게 번역 함)라고 부르든, 아니면 더 큰 것을 발견했기 때문에 그것을 중단하지 않더라도, 다이아몬드는 동일하게 유지되었습니다. 대조적으로 와가 우가와 함께 재미있는 그림을 조각하는 데 사용 된 나무 조각은 동일하게 유지되지 않았습니다. 변하기 쉬웠습니다. 이름이 항상 같은 경우에도 마찬가지입니다.

변수와 값은 모두 독립적으로 변경할 수 없습니다. 이 경우 불변의 객체입니다. 를 생성 한 후에 NSString는 수정할 수 없습니다. 이름을 부르고 전달할 수 있지만 동일하게 유지됩니다. 반면에 NSMutableString생성 후 setString메서드 를 호출하여 변경할 수 있습니다 .


waggawooga 비교를 사랑하십시오!
Michael K

원래 포스터를 필요 이상으로 혼동하지 않기 위해 : 변수가 객체가 아니라는 점은 훌륭하지만 실제로 변수는 "값을 나타내는 이름"으로 정의되지 않습니다. 변수의 이름 지정 될 수 있으며 값이 포함 된 저장 위치 를 나타냅니다 . 많은 프로그래밍 언어에서 변수의 이름을 지정할 필요가 없으며 많은 언어에서 동일한 변수가 둘 이상의 이름을 가질 수 있습니다.
Eric Lippert 2016 년

4

객체 자체와 해당 객체에 바인딩 된 변수 이름이라는 두 가지 개념을 혼합하기 때문에 길을 잃은 것 같습니다.

불변 개체는 변경할 수 없습니다. 기간. 그러나 불변 객체에 바인딩 된 변수 이름 (기호)은 다른 불변 객체에 바인딩되도록 수정할 수 있습니다 .

즉,이 두 줄에서 수행 한 작업은 다음과 같습니다.

  1. "Bob"값으로 불변 문자열 개체를 만듭니다.
  2. myName해당 객체에 심볼 바인딩
  3. 값이 "Mike"인 불변 문자열 개체를 만듭니다.
  4. myName해당 객체에 심볼 바인딩

2

당신의 당신의 유형은 아니다 NSString그것은 "입니다, 포인터NSString 불변 아니다". 객관적인 C에 대해서는 아무것도 모르지만 귀하의 예 @"Mike"에서 새 인스턴스를 만들고 포인터에NSString 할당하는 것으로 추측합니다 . 당신은 개체를 변경하지 않은 그래서 한 가리키는 단지로, 어떤 이 가리키는되었다. myNamemyName


0

변경 가능한 객체의 예는 다음과 같습니다. charC 의 배열 :

char str[10];

내용str 을 내 마음의 내용 으로 변경할 수 있습니다 (10자를 넘지 않는 한). C 문자열 라이브러리 함수에 의해 문자열로 인식 되려면 후행 0이 있어야하므로 최대 9 자 길이의 문자열을 보유 할 수 있습니다.

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

그리고 너무 weiter .

이것을 Java의 문자열 객체와 대조하십시오.

String foo = "Hello";

문자열 인스턴스 (문자 'H', 'e', ​​'l', 'l'및 'o'를 포함하는 메모리 청크)는 수정할 수 없습니다. 해당 문자열의 내용을 변경할 수 없습니다. 당신이 뭔가를 쓸 때

foo = foo + " World";

"Hello"인스턴스의 끝에 "World"를 추가하지 않습니다. 당신이 만드는 새로운 인스턴스를 여기에 "안녕하세요"를 복사 및 업데이트 foo가 새 문자열 인스턴스를 참조 할 수 있습니다.

foo자체는 문자열 인스턴스를 포함하지 않습니다. 그것은 단지 인스턴스 (C 또는 Obj-C의 포인터와 유사) 만 참조하므로 String과 같은 유형을 참조 유형이라고합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.