문제

D 2.0과 함께 놀면서 다음과 같은 문제를 발견했습니다.

Example 1:

pure string[] run1()
{
   string[] msg;
   msg ~= "Test";
   msg ~= "this.";
   return msg;
}

이것은 예상대로 컴파일하고 작동합니다.

클래스에 문자열 배열을 감싸려고 할 때 나는 이것을 작동시킬 수 없다는 것을 알았습니다.

class TestPure
{
    string[] msg;
    void addMsg( string s )
    {
       msg ~= s;
    }
};

pure TestPure run2()
{
   TestPure t = new TestPure();
   t.addMsg("Test");
   t.addMsg("this.");
   return t;
}

addmsg 함수가 부정 하므로이 코드는 컴파일되지 않습니다. 테스트 푸르 객체를 변경하기 때문에 그 기능을 순수하게 만들 수 없습니다. 내가 뭔가를 놓치고 있습니까? 아니면 이것이 제한입니까?

다음은 컴파일됩니다.

pure TestPure run3()
{
    TestPure t = new TestPure();
    t.msg ~= "Test";
    t.msg ~= "this.";
    return t;
}

~ = 연산자가 MSG 배열의 임박한 기능으로 구현되지 않습니까? 컴파일러가 어떻게 run1 함수에서 그것에 대해 불평하지 않습니까?

도움이 되었습니까?

해결책

v2.050 이후 D는 정의를 완화시켰다 pure 소위 "약한 순수한"기능도 받아들입니다. 이것은 "함수를 의미합니다"글로벌 변이 상태를 읽거나 쓰지 마십시오". 약하게 순수한 기능이 있습니다 동일하지 않습니다 기능적 언어 의미에서 순수한 기능으로. 유일한 관계는 그들이 OP의 예와 같이 약한 것들을 호출 할 수있는 "강하게 순수한"기능, 즉 "강하게 순수한"기능을한다는 것입니다.

이것으로 addMsg ~할 수 있다 (약하게)로 표시 pure, 로컬 변수 만 있으므로 this.msg 변경되었습니다 :

class TestPure
{
    string[] msg;
    pure void addMsg( string s )
    {
       msg ~= s;
    }
};

물론 이제 (강하게) 사용할 수 있습니다. pure 기능 run2 수정없이.

pure TestPure run2()
{
   TestPure t = new TestPure();
   t.addMsg("Test");
   t.addMsg("this.");
   return t;
}

다른 팁

다른 사람들은 이미 AddMSG가 순수하지 않으며 물체의 상태를 돌연변이하기 때문에 순수 할 수 없다고 지적했습니다.

순수하게 만드는 유일한 방법은 변경 사항을 캡슐화하는 것입니다. 이를 수행하는 가장 쉬운 방법은 반환 돌연변이를 통한 것이며,이를 구현하는 두 가지 방법이 있습니다.

첫째, 다음과 같이 할 수 있습니다.

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

순수한 함수 내부 에서이 참조는 실제로 const이므로 이전 배열을 복사해야합니다. 최종 크기의 새로운 배열을 할당 한 다음 자신의 요소를 복사하여 사본을 더 잘 수행 할 수 있습니다. 이 기능을 사용하여 다음과 같이 사용합니다.

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

이런 식으로, 돌연변이는 리턴 값을 통해 변화가 전달 된 각 순수한 기능에 국한된다.

시험판을 작성하는 대체 방법은 구성원에게 전달하기 전에 구성원을 구성하고 모든 돌연변이를 수행하는 것입니다.

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

도움이되기를 바랍니다.

순수한 기능의 정의를 검토하십시오 :

순수한 기능은 동일한 인수에 대해 동일한 결과를 생성하는 기능입니다. 이를 위해 순수한 기능 :

  • 모두 변하지 않거나 암시 적으로 변환 할 수있는 매개 변수가 있습니다.
  • 글로벌 변이 상태를 읽거나 쓰지 않습니다

순수한 기능을 사용하는 효과 중 하나는 안전하게 평행 할 수 있다는 것입니다. 그러나 클래스 인스턴스를 동시에 수정하여 동기화 문제를 일으킬 수 있기 때문에 기능의 여러 인스턴스를 병렬로 실행하는 것이 안전하지 않습니다.

생각한다 코드가 개념적으로 정확하다는 것입니다. 그러나 컴파일러의 시맨틱 분석이 뇌만큼 좋지 않은 경우를 발견했을 수 있습니다.

클래스 소스를 사용할 수없는 경우를 고려하십시오. 이 경우 컴파일러는 addMsg 멤버 변수 만 수정하여 순수한 함수에서 호출 할 수 없습니다.

귀하의 경우이를 허용하려면 이러한 유형의 사용에 대해 특별한 케이스 처리가 필요합니다. 추가 된 모든 특별 사례 규칙은 언어를 더욱 복잡하게 만듭니다 (또는 문서화되지 않은 상태로두면 휴대가 덜 휴대용).

직감이지만이 기능이 항상 같은 결과를 반환하는 것은 아닙니다.

참조, 일부 객체에 대한 참조를 반환하고 객체에는 항상 동일한 데이터가 포함되어 있지만 동일한 함수로 여러 호출로 반환 된 객체는 동일하지 않습니다. 즉, 동일한 메모리 주소가 없습니다.

객체에 대한 참조를 반환하면 기본적으로 메모리 주소를 반환하는데, 이는 여러 통화마다 다릅니다.

그것을 생각하는 또 다른 방법은 반환 값의 일부는 객체의 메모리 주소이며, 일부 글로벌 상태에 의존하며, 함수의 출력이 글로벌 상태에 의존하는 경우 순수하지 않습니다. 지옥, 그것에 의존 할 필요조차 없습니다. 함수가 글로벌 상태를 읽는 한 순수하지 않습니다. "새로운"라고 부르면 글로벌 주를 읽고 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top