2012-03-29 4 views
7

에 할당 범위/반복자는 :D2 : 코드 다음 사항을 고려 배열 슬라이스

enum size = 16; 
double[size] arr1 = [...]; 
double[size] arr2 = [...]; 
process = (double x) { return (x + 1); }; 

arr2[] = map!(process)(arr1[]); // here 

내 일반 배열에 다시 map의 문제 변환 결과가있다. 문제는 map뿐만 아니라 take, repeat 및 범위에서 작동하는 std.algorithmstd.range의 모든 훌륭한 도구에도 적용됩니다.

이 과제에서 나는 Error: cannot implicitly convert expression (map(arr1[])) of type Result to double[]을 얻습니다. 배열을 배열없이 사용하지 않고 평가할 수있는 방법은 무엇입니까?

uint i = 0; 
foreach (x; map!(process)(arr1[])) { 
    arr2[i] = x; 
    i++; 
} 

?

덧붙여 말하자면 누군가가 설명해주십시오. 왜 map!(process)(arr1) 대신에 map!(process)(arr1[])으로 전화해야합니까? 정적 배열은 반복 방법에 대해 동적 함수와 호환되지 않아야합니까? 아니면 무언가를 얻지 못합니까?

또한 간단한 열거 구문 foreach (index, item; sequence)이 범위에서 작동하지 않는 것 같습니다. 해결 방법이 있습니까? 이유는 배열 슬라이스에 범위를 할당 할 수없는 이유와 같습니다. 예 : 단순히 배열에 할당 mapfilter 반환 범위가 아닌 배열과 같은

답변

11

기능이 작동하기 위하여려고하는 stringwstring에 할당하는 것보다 더 이상 작동하지 않을. 그들은 서로 다른 유형입니다. 또한 많은 범위 기반 함수 (mapfilter 포함)의 경우 반환하는 범위는 실제로 불필요한 계산을 피하기 위해 게으르므로 배열과의 호환성이 훨씬 떨어집니다. 해결책은 std.array.array을 사용하는 것입니다. 범위는 범위를 가져 와서 동적 배열을 만듭니다. 그래서, 당신은 당신이 실제로 필요하기 전에 불필요한 계산을 초래할 수 있기 때문에 나는 배열로 범위를 변환하지 권합니다, 그것은 새로운 배열을 할당하는 것을 의미, 그러나

auto arr = array(map!process(origArray)); 

할 수 있습니다. 실제로 배열이 필요한 경우에는 반드시 std.array.array를 사용하여 범위를 변환하십시오. 그러나 실제 배열이 필요하지 않으면 범위에서 작업하는 것이 더 효율적일 수 있습니다. 그러나 결과를 정적 배열로 변환하려면 역동적 인 배열로 변환하려면 루프의 각 요소를 할당하는 것이 좋습니다 (어쩌면 map을 건너 뜁니다). std.array.array를 사용하면됩니다. 일단 정적 배열에 할당하면 사용하지 않을 동적 배열을 할당하게됩니다. 기억의 낭비입니다.

또한 범위 기반 함수를 사용하는 정적 배열을 사용하면 범위 기반 함수를 처리 할 동적 배열을 얻기 위해 정적 배열을 잘라내야하며 동적 배열이 범위를 벗어나는 경우 위험 할 수 있습니다 정적 배열이 선언 된 다음 더 이상 존재하지 않는 데이터에 대한 참조가 누출됩니다. 예를 들어,

auto func() 
{ 
    int[5] arr; 
    return map!process(arr[]); 
} 

은 매우 나쁩니다. 그러나 슬라이스를 사용하여 끝내고 정적 배열이 포함 된 범위를 종료하기 전에 더 이상 참조하지 않는 범위 (작성된 범위 포함)가 없으면 아무 문제가 없습니다. 입니다.

고정 배열을 조각 내야한다는 질문에 대해서는 별도의 질문으로 질문해야하지만 관련 질문은 this onethis one입니다. IFl (Implicit Function Template Instantiation)은 주어진 정확한 유형을 사용하여 인스턴스화하며 정적 배열은 동적 배열이나 범위가 아니므로 특별히 동적 배열이나 범위는 정적 배열로 컴파일되지 않습니다. 컴파일러 동적 배열을 명시 적으로 가져 오는 함수에 대해 정적 배열을 암시 적으로 슬라이스하여 동적 배열로 변환하지만 암시 적 변환은 템플릿 인스턴스화에서 발생하지 않으므로 명시 적으로 정적 배열을 분할하여 범위 지정 배열로 전달해야합니다. 기반 기능.

인덱스와 범위와 함께 foreach를 사용하는 것에 대한 질문은 동일한 질문에서 여러 질문을하지 않아야합니다. 가지고있는 각 질문마다 별도의 질문을 올리십시오. 무엇 그래도 내려 온다

foreach(elem; range) 
{ 
    //stuff 
} 

for(; !range.empty; range.popFront()) 
{ 
    auto elem = range.front; 
    //stuff 
} 

에 가까운 무언가로 저하됩니다 그리고 그 모든 인덱스를 포함하지 않습니다. 그것은 당신을 위해 인덱스 변수를 만들 수 변경 될 수 있지만 모든 반복에서 (일반적으로 괜찮을 것입니다) 같은 하나씩 반복되는 인덱스를 범위가 항상 이해가되지 않습니다, 그래서 hasn 끝났어. 그것은 자신의 카운터를 추가 할 정도로 간단합니다.

{ 
    size_t i; 
    foreach(elem; range) 
    { 
     //stuff 
     ++i; 
    } 
} 

opApply

의 foreach와 인덱스를 사용하여지지 않지만 범위없고, 범위 기반 함수가 작동하지 않는다.

+0

고마워요, 조나단! 나는 범위와 배열이 다른 유형이지만, 범위가 한정적이고 배열의 요소와 형식이 호환되는 한 범위를 배열로 변환 할 수 있기 때문에 D가 일종의 암시 적 변환을 구현할 수 있다고 생각했습니다. 스택과 힙 할당의 차이, 그리고 배열 izing의 계산 및 메모리 오버 헤드에 대해 알고 있지만 경고를 주셔서 감사합니다. :) 또한 IFTI로 명확히 해 주셔서 감사합니다.이 권리를 이해하면 미래에 이것이 바뀔 수도 있습니다. 암시 적 슬라이스 정적 배열을 허용하지만, 이제 우리는 불완전 함으로 인해이 방법을 사용해야합니다. – toriningen

+0

정적 배열을 동적 배열로 암시 적으로 변환하기 위해 IFTI _might_가 변경되었지만 의심 스럽습니다. 여전히 템플리트 함수가 정적 배열을 가질 수 있어야합니다 (템플릿 인스턴스화를 위해 변환하는 것이 좋지 않을 수 있습니다). 그리고 IFTI는 작동하는 암시 적 변환을 찾을 때까지 계속 시도하지 않습니다. 많은 템플릿의 의미론). 따라서 정적 배열을 영역 기반 함수에 전달하기 위해 항상 슬라이스를 분할해야한다고 생각하지만 적어도 문제를 줄이려면 어느 정도 개선이 이루어질 수 있습니다. –

관련 문제