Programing

가변 구조체는 왜 "악"입니까?

lottogame 2020. 2. 15. 19:35
반응형

가변 구조체는 왜 "악"입니까?


SO에 대한 토론에 이어 이미 가변성 구조체가 "이블"이라는 말을 여러 번 읽었습니다 (이 질문 에 대한 답변에서와 같이 ).

C #의 가변성 및 구조체의 실제 문제는 무엇입니까?


Structs는 값 유형으로, 전달 될 때 복사됩니다.

따라서 사본을 변경하면 원본이 아닌 해당 사본 만 변경되고 다른 사본은 변경되지 않습니다.

구조체가 변경 불가능한 경우 값을 전달하여 생성 된 모든 자동 사본은 동일합니다.

변경하려면 수정 된 데이터로 구조체의 새 인스턴스를 만들어 의식적으로 변경해야합니다. (사본이 아님)


시작 위치 ;-p

Eric Lippert의 블로그 는 항상 인용문으로 좋습니다.

이것이 가변 값 유형이 악한 또 다른 이유입니다. 항상 값 유형을 변경할 수 없도록하십시오.

먼저 변경 사항을 쉽게 잃는 경향이 있습니다. 예를 들어 목록에서 항목을 가져 오는 경우 :

Foo foo = list[0];
foo.Name = "abc";

그게 뭐에요? 유용한 것은 없습니다 ...

속성과 동일 :

myObj.SomeProperty.Size = 22; // the compiler spots this one

당신이 강제로 :

Bar bar = myObj.SomeProperty;
bar.Size = 22;
myObj.SomeProperty = bar;

덜 중요한 것은 크기 문제입니다. 가변 객체 는 여러 속성을 갖는 경향 이 있습니다. 당신이 가진 구조체 경우 아직 intS, A string하는 DateTime과를 bool, 당신은 매우 신속하게 많은 메모리를 구울 수 있습니다. 클래스를 사용하면 여러 호출자가 동일한 인스턴스에 대한 참조를 공유 할 수 있습니다 (참조는 작음).


나는 악을 말하지 는 않지만 가변성은 종종 최대 기능을 제공하기 위해 프로그래머 측의 지나치게 열망의 신호입니다. 실제로, 이것은 종종 필요하지 않으며 결과적으로 인터페이스를 더 작고 사용하기 쉽고 잘못 사용하기 어렵게 만듭니다 (= 더 견고 함).

경쟁 조건에서의 읽기 / 쓰기 및 쓰기 / 쓰기 충돌이 이에 해당합니다. 쓰기는 유효한 연산이 아니기 때문에 불변 구조에서 발생할 수 없습니다.

또한 변경이 거의 필요하지 않다고 주장합니다 . 프로그래머는 단지 미래에 있을 것이라고 생각 합니다 . 예를 들어 날짜를 변경하는 것은 의미가 없습니다. 오히려 이전 날짜를 기준으로 새 날짜를 만드십시오. 이것은 저렴한 작업이므로 성능을 고려하지 않습니다.


가변적 인 구조체는 악하지 않습니다.

고성능 환경에서는 절대적으로 필요합니다. 예를 들어 캐시 라인 및 가비지 수집이 병목 현상이되는 경우.

나는 완벽하게 유효한 유스 케이스 "evil"에서 불변 구조체의 사용을 호출하지 않을 것이다.

C #의 구문이 값 형식 또는 참조 형식의 멤버 액세스를 구별하는 데 도움이되지 않는 점을 알 수 있으므로 변경 불가능한 구조체 보다 불변성을 강제 하는 불변 구조체 선호 합니다.

그러나 불변 구조체를 단순히 "악"으로 표시하는 대신 언어를 받아들이고보다 유용하고 건설적인 엄지 손가락 규칙을 옹호하는 것이 좋습니다.

예를 들어 "struct는 값 유형이며 기본적으로 복사됩니다. 복사하지 않으려면 참조가 필요합니다" 또는 "readonly structs를 먼저 사용하십시오" .


공개적으로 변경 가능한 필드 또는 속성을 가진 구조체는 악하지 않습니다.

.net이 그렇지 않은 메소드와 구별 할 수있는 방법을 제공하지 않기 때문에 "this"를 변경하는 구조 메소드 (속성 설정자와는 구별됨)는 다소 악의적입니다. "this"를 변경하지 않는 구조 메소드는 방어 적 복사가 필요없는 읽기 전용 구조체에서도 호출 할 수 있어야합니다. "this"를 변경하는 메소드는 읽기 전용 구조체에서 호출 할 수 없어야합니다. .net은 읽기 전용 구조체에서 "this"가 호출되는 것을 수정하지 않는 구조체 메소드를 금지하고 싶지 않지만 읽기 전용 구조체의 변경을 허용하지 않으려면 구조체를 읽기 전용으로 복사합니다. 두 세계에서 최악의 상황이 될 수 있습니다.

그러나 읽기 전용 컨텍스트에서 자체 변경 메소드를 처리하는 데 문제점이 있지만, 변경 가능한 구조체는 종종 변경 가능한 클래스 유형보다 훨씬 우수한 의미를 제공합니다. 다음 세 가지 메소드 서명을 고려하십시오.

struct PointyStruct {public int x, y, z;};
PointyClass 클래스 {public int x, y, z;};

void Method1 (PointyStruct foo);
void Method2 (참조 PointyStruct foo);
void Method3 (PointyClass foo);

각 방법에 대해 다음 질문에 답하십시오.

  1. 메소드가 "안전하지 않은"코드를 사용하지 않는다고 가정하면 foo를 수정할 수 있습니까?
  2. 메소드가 호출되기 전에 'foo'에 대한 외부 참조가 없으면 외부 참조가 존재할 수 있습니까?

답변:

질문 1 :
Method1(): 아니오 (명확한 의도)
Method2() : 예 (명확한 의도)
Method3() : 예 (불확실한 의도)
질문 2 :
Method1(): 아니오
Method2(): 아니오 ( 아니요 안전하지 않은 경우)
Method3() : 예

Method1은 foo를 수정할 수 없으며 참조를 얻지 않습니다. Method2는 foo에 대한 단기 참조를 가져옵니다. foo는 반환 될 때까지 순서에 상관없이 foo 필드를 여러 번 수정할 수 있지만 해당 참조를 유지할 수는 없습니다. 안전하지 않은 코드를 사용하지 않으면 Method2가 리턴하기 전에 'foo'참조로 작성된 모든 사본이 사라집니다. Method2는 Method2와 달리 foo에 대해 무차별 적으로 공유 할 수있는 참조를 얻습니다. foo를 전혀 변경하지 않거나 foo를 변경 한 다음 반환하거나 다른 스레드에 대한 foo에 대한 참조를 제공하여 나중에 임의의 방식으로 임의의 방식으로 변경시킬 수 있습니다.

구조의 배열은 훌륭한 의미를 제공합니다. Rectangle 유형의 RectArray [500]이 주어진 경우, 예를 들어 요소 123을 요소 456에 복사 한 다음 나중에 요소 456을 방해하지 않으면 서 요소 123의 너비를 555로 설정하는 방법이 명확하고 분명합니다. "RectArray [432] = RectArray [321 ]; ...; RectArray [123] .Width = 555; ". Rectangle이 Width라는 정수 필드를 가진 구조체라는 것을 알면 위의 명령문에 대해 모두 알아야 할 것입니다.

이제 RectClass가 Rectangle과 동일한 필드를 가진 클래스이고 RectClass 유형의 RectClassArray [500]에서 동일한 작업을 수행하려고한다고 가정하십시오. 아마도 배열은 변경 가능한 RectClass 객체에 대해 사전 초기화 된 500 개의 불변 참조를 보유해야합니다. 이 경우 올바른 코드는 "RectClassArray [321] .SetBounds (RectClassArray [456]); ...; RectClassArray [321] .X = 555;"와 같은 코드입니다. 아마도 배열은 변경되지 않을 인스턴스를 보유한다고 가정하므로 적절한 코드는 "RectClassArray [321] = RectClassArray [456]; ...; RectClassArray [321] = New RectClass (RectClassArray [321) ]); RectClassArray [321] .X = 555; " 무엇을 해야하는지 알기 위해서는 RectClass에 대해 더 많이 알아야합니다 (예 : 복사 생성자, copy-from 메소드 등을 지원합니까). ) 및 배열의 ​​의도 된 사용법. 구조체를 사용하는 것만 큼 깨끗한 곳은 없습니다.

확실히 배열 이외의 컨테이너 클래스가 구조체 배열의 깨끗한 의미를 제공하는 좋은 방법은 없습니다. 컬렉션으로 문자열을 색인화하기를 원하는 경우 가장 좋은 방법은 인덱스에 대한 문자열, 일반 매개 변수 및 전달되는 대리자를 허용하는 일반 "ActOnItem"메서드를 제공하는 것입니다. 제네릭 매개 변수와 컬렉션 항목을 모두 참조하십시오. 그것은 구조체 배열과 거의 동일한 의미를 허용하지만 vb.net 및 C # 사람들이 멋진 구문을 제공하도록 설득 할 수 없다면 코드가 성능이 우수하더라도 (일반 매개 변수를 전달해도 코드가 어색해 보입니다) 정적 대리자를 사용할 수 있으며 임시 클래스 인스턴스를 만들 필요가 없습니다.

개인적으로, 나는 증오 Eric Lippert et al. 가변 값 유형과 관련하여 분출합니다. 그들은 모든 곳에서 사용되는 무차별 참조 유형보다 훨씬 더 명확한 의미를 제공합니다. .net의 값 유형 지원에 대한 일부 제한 사항에도 불구하고 변경 가능한 값 유형이 다른 유형의 엔티티보다 더 적합한 경우가 많이 있습니다.


값 유형은 기본적으로 불변의 개념을 나타냅니다. Fx, 정수, 벡터 등과 같은 수학적 값을 가지고 수정하는 것은 의미가 없습니다. 그것은 가치의 의미를 재정의하는 것과 같습니다. 값 유형을 변경하는 대신 다른 고유 한 값을 할당하는 것이 더 합리적입니다. 속성의 모든 값을 비교하여 값 유형이 비교된다는 사실에 대해 생각하십시오. 요점은 속성이 동일하면 해당 값의 동일한 범용 표현이라는 것입니다.

Konrad가 언급했듯이 값은 상태 또는 컨텍스트 의존성을 가진 시간 객체의 인스턴스가 아닌 고유 한 시점을 나타내므로 날짜를 변경하는 것이 의미가 없습니다.

이것이 당신에게 의미가 있기를 바랍니다. 실제 세부 사항보다 값 유형으로 캡처하려는 개념에 대한 자세한 내용입니다.


프로그래머의 관점에서 예측할 수없는 행동으로 이어질 수있는 또 다른 몇 가지 사례가 있습니다. 여기 몇 개가 있습니다.

  1. 변경할 수없는 값 유형 및 읽기 전용 필드

// Simple mutable structure. 
// Method IncrementI mutates current state.
struct Mutable
{
    public Mutable(int i) : this() 
    {
        I = i;
    }

    public void IncrementI() { I++; }

    public int I {get; private set;}
}

// Simple class that contains Mutable structure
// as readonly field
class SomeClass 
{
    public readonly Mutable mutable = new Mutable(5);
}

// Simple class that contains Mutable structure
// as ordinary (non-readonly) field
class AnotherClass 
{
    public Mutable mutable = new Mutable(5);
}

class Program
{
    void Main()
    {
        // Case 1. Mutable readonly field
        var someClass = new SomeClass();
        someClass.mutable.IncrementI();
        // still 5, not 6, because SomeClass.mutable field is readonly
        // and compiler creates temporary copy every time when you trying to
        // access this field
        Console.WriteLine(someClass.mutable.I);

        // Case 2. Mutable ordinary field
        var anotherClass = new AnotherClass();
        anotherClass.mutable.IncrementI();

        //Prints 6, because AnotherClass.mutable field is not readonly
        Console.WriteLine(anotherClass.mutable.I);
    }
}

  1. 가변 값 유형 및 배열

Mutable 구조체의 배열이 있고 해당 배열의 첫 번째 요소에 대해 IncrementI 메소드를 호출한다고 가정하십시오. 이 전화에서 어떤 행동을 기대하십니까? 배열의 값을 변경해야합니까 아니면 사본 만 변경해야합니까?

Mutable[] arrayOfMutables = new Mutable[1];
arrayOfMutables[0] = new Mutable(5);

// Now we actually accessing reference to the first element
// without making any additional copy
arrayOfMutables[0].IncrementI();

//Prints 6!!
Console.WriteLine(arrayOfMutables[0].I);

// Every array implements IList<T> interface
IList<Mutable> listOfMutables = arrayOfMutables;

// But accessing values through this interface lead
// to different behavior: IList indexer returns a copy
// instead of an managed reference
listOfMutables[0].IncrementI(); // Should change I to 7

// Nope! we still have 6, because previous line of code
// mutate a copy instead of a list value
Console.WriteLine(listOfMutables[0].I);

따라서 변경 가능한 구조체는 자신과 팀의 나머지 구성원이 자신이하는 일을 명확하게 이해하는 한 악한 것이 아닙니다. 그러나 프로그램 동작이 예상 한 동작과 다를 경우 코너가 너무 많아서 생성하기가 어렵고 오류를 이해하기가 어려울 수 있습니다.


C / C ++와 같은 언어로 프로그래밍 한 적이 있다면 구조체를 변경 가능하게 사용하는 것이 좋습니다. 심판과 함께 그들을지나 치면 잘못 될 수있는 것은 없습니다. 내가 찾은 유일한 문제는 C # 컴파일러의 제한 사항이며 경우에 따라 Copy 대신 멍청한 일이 구조체에 대한 참조를 사용하도록 강요 할 수 없습니다 (구조가 C # 클래스의 일부 인 경우와 같습니다) ).

그래서, 가변 구조체 악, C #을하고있다되지 않습니다 만들어 이를 악을. 나는 C ++에서 항상 가변 구조체를 사용하며 매우 편리하고 직관적입니다. 반대로 C #에서는 객체를 처리하는 방식 때문에 클래스의 멤버로 구조체를 완전히 포기했습니다. 그들의 편의는 우리를 희생시켰다.


1,000,000 개의 구조체가 있다고 상상해보십시오. bid_price, offer_price (아마도 십진수) 등과 같은 항목으로 주식을 나타내는 각 구조체는 C # / VB에 의해 생성됩니다.

관리되지 않는 힙에 할당 된 메모리 블록에 배열이 생성되어 다른 원시 코드 스레드가 동시에 배열에 액세스 할 수 있다고 가정합니다 (어쩌면 수학을 수행하는 일부 고성능 코드).

C # / VB 코드가 가격 변동에 대한 시장 피드를 듣고 있다고 상상해보십시오.이 코드는 어레이의 일부 요소 (어떤 보안을 위해)에 액세스 한 다음 일부 가격 필드를 수정해야 할 수 있습니다.

이것이 초당 수십 또는 수십만 번 수행되고 있다고 상상해보십시오.

사실, 사실을 직시하자.이 경우에 우리는이 구조체가 변경 가능하기를 원합니다. 다른 네이티브 코드와 공유되기 때문에 복사본을 만드는 것이 도움이되지 않기 때문입니다. 이러한 업데이트 속도로 120 바이트 정도의 구조체를 복사하는 것은 어리석기 때문에 특히 업데이트가 실제로 1 ~ 2 바이트에 영향을 미칠 수 있기 때문입니다.

휴고


구조체로 의도 된 것 (포인터로 사용되지 않을 때 C #, Visual Basic 6, Pascal / Delphi, C ++ 구조체 유형 (또는 클래스))을 고수하면 구조체가 복합 변수 이상이 아님을 알 수 있습니다 . 즉, 공통 이름 (멤버를 참조하는 레코드 변수)으로 묶은 변수 세트로 취급합니다.

OOP에 깊이 익숙해 져있는 많은 사람들을 혼동 할 것임을 알고 있지만, 올바르게 사용한다면 그러한 것들이 본질적으로 악하다고 말할 충분한 이유는 아닙니다. 일부 구조는 의도 한대로 변경할 수 없지만 (Python의 경우 namedtuple) 고려해야 할 또 다른 패러다임입니다.

예 : 구조체에는 많은 메모리가 필요하지만 다음을 수행하여 메모리가 더 많지는 않습니다.

point.x = point.x + 1

다음과 비교 :

point = Point(point.x + 1, point.y)

메모리 소비는 변하지 않는 경우에 적어도 동일하거나 더 많을 것입니다 (언어에 따라 현재 스택의 경우 일시적 임에도 불구하고).

그러나 마지막으로 구조는 객체가 아닌 구조 입니다. POO에서 ​​객체의 주요 속성은 그들의 정체성 이며, 대부분의 경우 메모리 주소를 넘지 않습니다. Struct는 데이터 구조를 나타내며 (적절한 개체가 아니므로 ID가 없음) 데이터를 수정할 수 있습니다. 다른 언어에서, 레코드 ( 파스칼의 경우와 마찬가지로 struct 대신 )는 단어이며 동일한 목적을 가지고 있습니다 : 데이터 레코드 변수, 파일에서 읽고 수정하고 파일로 덤프하기위한 것입니다. 많은 언어에서 레코드에서 데이터 정렬을 정의 할 수도 있지만, 반드시 개체라고하는 것은 아닙니다.

좋은 예를 원하십니까? Structs는 파일을 쉽게 읽는 데 사용됩니다. 파이썬은 이 라이브러리를 가지고 있습니다. 왜냐하면 객체 지향적이고 구조체를 지원하지 않기 때문에 다른 방법으로 구현해야했기 때문에 다소 추한 것입니다. 구조체를 구현하는 언어에는 내장 기능이 있습니다. Pascal 또는 C와 같은 언어로 적절한 구조체로 비트 맵 헤더를 읽으십시오. 구조체가 올바르게 작성되고 정렬되면 Pascal에서는 레코드 기반 액세스를 사용하지 않고 임의의 이진 데이터를 읽는 기능을 사용합니다. 따라서 파일 및 직접 (로컬) 메모리 액세스의 경우 구조체가 객체보다 낫습니다. 오늘날 우리는 JSON과 XML에 익숙하기 때문에 바이너리 파일의 사용과 부작용으로 구조체의 사용을 잊어 버립니다. 그러나 그렇습니다. 그것들은 존재하며 목적이 있습니다.

그들은 악하지 않습니다. 올바른 목적으로 사용하십시오.

망치로 생각하면 나사를 못으로 취급하고 나사가 벽에 빠지기가 더 어려워 나사의 잘못이되어 악의적 인 사람이 될 것입니다.


무언가가 변이 될 수 있다면, 그것은 정체성의 감각을 얻는다.

struct Person {
    public string name; // mutable
    public Point position = new Point(0, 0); // mutable

    public Person(string name, Point position) { ... }
}

Person eric = new Person("Eric Lippert", new Point(4, 2));

Person변경 가능 하기 때문에 Eric 복제, 복제 이동 및 원본 파괴 보다 Eric의 위치 변경 에 대해 생각 하는 것이 더 자연 스럽습니다 . 두 작업 모두의 내용을 변경하는 데 성공 하지만 하나는 다른 것보다 직관적입니다. 마찬가지로 Eric을 수정하는 방법에 대해 참조로 Eric을 전달하는 것이 더 직관적입니다. 에릭의 복제품을 제공하는 것은 거의 항상 놀라운 일이 될 것입니다. 돌연변이 원하는 사람 은 참조를 요청해야합니다. 그렇지 않으면 잘못된 일을합니다.eric.positionPersonPerson

유형을 변경할 수 없게하면 문제가 해결됩니다. 내가 수정할 수 없다면 eric, eric또는의 복제본을 받든 나에게 아무런 영향을 미치지 않습니다 eric. 보다 일반적으로, 관찰 가능한 모든 상태가 다음 중 하나 인 멤버에 유지되는 경우 유형에 따라 값을 전달하는 것이 안전합니다.

  • 불변의
  • 참조 유형
  • 가치를 지킬 안전

이러한 조건이 충족되면 변경 가능한 값 형식은 얕은 복사본으로 인해 수신기가 원본 데이터를 수정할 수 있기 때문에 참조 형식처럼 작동합니다.

불변의 직관성은 Person당신이하려는 일에 달려 있습니다. 사람에 대한 일련의 데이터Person 만 나타내는 경우 에는 직관적이지 않습니다. 변수는 객체가 아닌 추상적 인 값을 나타냅니다 . (이 경우 이름을으로 바꾸는 것이 더 적절할 것입니다 .) 실제로 사람 자체를 모델링하는 경우 수정하려는 생각의 함정을 피하더라도 복제본을 지속적으로 생성 및 이동한다는 아이디어는 어리 석습니다. 원래. 이 경우 단순히 참조 유형 (즉, 클래스)을 만드는 것이 더 자연 스럽습니다 .PersonPersonDataPersonPerson

물론, 함수형 프로그래밍이 우리에게 모든 것을 불변 으로 만드는 데 이점이 있다는 것을eric 알았지 만 (누구도 그를 참조 하고 돌연변이 시킬 수는 없습니다 ), OOP에서는 관용적이지 않기 때문에 다른 사람과 일하는 사람에게는 여전히 직관적이지 않습니다. 암호.


구조체와 관련이 없으며 C # 과도 관련이 없지만 Java에서는 해시 맵의 키와 같은 가변 객체에 문제가 발생할 수 있습니다. 맵에 추가 한 후 변경하고 해시 코드를 변경 하면 악한 일이 발생할 수 있습니다.


개인적으로 코드를 볼 때 다음은 꽤 어색해 보입니다.

data.value.set (data.value.get () + 1);

단순히보다는

data.value ++; 또는 data.value = data.value + 1;

데이터 캡슐화는 클래스를 전달할 때 유용하며 제어 된 방식으로 값을 수정하려고합니다. 그러나 공개 세트를 가지고 있고 전달 된 값으로 값을 설정하는 것 이상의 기능을 수행 할 때 단순히 공개 데이터 구조를 단순히 전달하는 것보다 어떻게 개선됩니까?

클래스 내에서 개인 구조를 만들 때 변수 구조를 하나의 그룹으로 구성하기 위해 해당 구조를 만들었습니다. 클래스 범위 내에서 해당 구조를 수정하고 해당 구조의 사본을 얻지 않고 새 인스턴스를 만들 수 있기를 원합니다.

나에게 이것은 공용 변수를 구성하는 데 사용되는 구조의 유효한 사용을 막습니다. 액세스 제어를 원한다면 클래스를 사용합니다.


Eric Lippert 씨의 사례에는 몇 가지 문제가 있습니다. 구조체가 복사되는 지점과 조심하지 않으면 어떻게 문제가 될 수 있는지 설명하기 위해 고안되었습니다. 예제를 보면 프로그래밍 습관이 좋지 않고 구조체 나 클래스에 문제가없는 것으로 보았습니다.

  1. 구조체에는 공개 멤버 만 있어야하며 캡슐화가 필요하지 않습니다. 그렇다면 실제로 유형 / 클래스 여야합니다. 실제로 같은 것을 말하기 위해 두 가지 구성이 필요하지 않습니다.

  2. 구조체를 묶는 클래스가 있으면 클래스의 메서드를 호출하여 멤버 구조체를 변경합니다. 이것이 좋은 프로그래밍 습관으로 할 것입니다.

올바른 구현은 다음과 같습니다.

struct Mutable {
public int x;
}

class Test {
    private Mutable m = new Mutable();
    public int mutate()
    { 
        m.x = m.x + 1;
        return m.x;
    }
  }
  static void Main(string[] args) {
        Test t = new Test();
        System.Console.WriteLine(t.mutate());
        System.Console.WriteLine(t.mutate());
        System.Console.WriteLine(t.mutate());
    }

구조체 자체의 문제가 아닌 프로그래밍 습관의 문제 인 것 같습니다. Structs는 변경 가능해야합니다. 즉 아이디어와 의도입니다.

변경 결과는 예상대로 동작합니다.

1 아무 키나 눌러 계속하십시오. . .


변경 가능한 데이터에는 많은 장점과 단점이 있습니다. 백만 달러의 단점은 앨리어싱입니다. 여러 장소에서 동일한 값을 사용하고 있고 그 중 하나가 값을 변경하면 해당 값을 사용하는 다른 장소로 마술처럼 변경된 것으로 보입니다. 이것은 경쟁 조건과 관련이 있지만 동일하지는 않습니다.

백만 달러의 이점은 때로는 모듈성입니다. 가변 상태를 사용하면 알 필요가없는 코드에서 변경 정보를 숨길 수 있습니다.

통역사 기술 은 이러한 트레이드 오프에 대해 자세히 설명하고 몇 가지 예를 제공합니다.


올바르게 사용하면 악하다고 생각하지 않습니다. 나는 그것을 프로덕션 코드에 넣지 않을 것이지만 구조체의 수명이 비교적 작은 구조적 단위 테스트 모의와 같은 것을 원할 것입니다.

Eric 예제를 사용하면 해당 Eric의 두 번째 인스턴스를 작성하려고하지만 테스트의 특성 (예 : 복제, 수정)으로 조정합니다. 테스트 스크립트의 나머지 부분에 Eric2를 사용하려는 경우가 아니라면 테스트 스크립트의 나머지 부분에 Eric2를 사용하는 경우 Eric의 첫 번째 인스턴스에서 어떤 일이 발생하는지는 중요하지 않습니다.

이것은 특정 객체 (구조 점)를 얕게 정의하는 레거시 코드를 테스트하거나 수정하는 데 주로 유용하지만 불변의 구조를 사용하면 성가신 사용을 막을 수 있습니다.

참고 URL : https://stackoverflow.com/questions/441309/why-are-mutable-structs-evil



반응형