Swift 어레이 할당에 일관성이 없는 이유(레퍼런스나 딥 카피 모두)가 있습니까?
저는 문서를 읽고 있는데 언어의 디자인 결정에 대해 끊임없이 고개를 가로젓고 있습니다.하지만 정말 혼란스러운 것은 어레이의 처리 방식입니다.
나는 운동장으로 달려가 이것들을 시험해 보았다.너도 한번 해봐.첫 번째 예는 다음과 같습니다.
var a = [1, 2, 3]
var b = a
a[1] = 42
a
b
서 ★★★★a
★★★★★★★★★★★★★★★★★」b
다이다[1, 42, 3]
됩니다.OK어레이가 참조됩니다.네!
다음으로 다음 예를 제시하겠습니다.
var c = [1, 2, 3]
var d = c
c.append(42)
c
d
c
[1, 2, 3, 42]
d
[1, 2, 3]
. . . . . . .d
마지막 예에서는 변경 내용을 확인했지만 이 예에서는 표시되지 않습니다.서류상으로는 길이가 바뀌었기 때문이라고 합니다.
이건 어때?
var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e
f
e
[4, 5, 3]
다중 인덱스 치환도 가능합니다f
길이가 변경되지 않았는데도 여전히 변화가 나타나지 않습니다.
요약하면 어레이에 대한 공통 참조는 1개의 요소를 변경하면 변경되지만 여러 요소를 변경하거나 항목을 추가하면 복사본이 생성됩니다.
이것은 저에게 매우 서투른 디자인인 것 같습니다.제가 이렇게 생각하는 게 맞나요?어레이가 이렇게 동작해야 하는 이유를 알 수 없는 이유는 무엇입니까?
편집: 어레이가 변경되어 가치의 의미가 부여되었습니다.훨씬 더 제정신이야!
Xcode beta 3 버전(블로그 투고)에서는 어레이의 의미와 구문이 변경되었기 때문에 이 질문은 더 이상 적용되지 않습니다.다음 답변이 베타 2에 적용되었습니다.
퍼포먼스를 위해서입니다.기본적으로 어레이의 복사는 가능한 한 피하려고 합니다(또, 「C와 같은 퍼포먼스」라고 주장).언어책을 인용하려면:
어레이의 경우 어레이 길이를 수정할 수 있는 작업을 수행할 때만 복사가 수행됩니다.여기에는 항목을 추가, 삽입 또는 제거하거나, 배열 내의 항목 범위를 바꾸기 위해 범위 첨자를 사용하는 것이 포함됩니다.
이것이 조금 혼란스럽다는 것에 동의하지만, 적어도 어떻게 작동하는지에 대한 명확하고 간단한 설명이 있습니다.
또, 어레이가 일의로 참조되고 있는 것을 확인하는 방법, 어레이를 강제 카피하는 방법, 및 2개의 어레이가 스토리지를 공유하고 있는지를 확인하는 방법에 대해서도 설명합니다.
첨자 구문을 사용하여 새 값을 설정할 때 어레이가 복사되지 않습니다. 첨자 구문을 사용하여 단일 값을 설정해도 어레이의 길이가 변경될 수 있기 때문입니다.그러나 새 항목을 어레이에 추가하는 경우 어레이 길이를 수정해야 합니다.그러면 Swift가 새 값을 추가하는 시점에 어레이의 새 복사본을 생성하라는 메시지를 표시합니다.따라서 a는 배열의 독립된 복사본입니다.
이 메뉴얼의 「어레이의 할당과 카피 동작」의 항 전체를 참조해 주세요.어레이내의 아이템의 범위를 교환하면, 어레이는 모든 아이템의 카피를 취득합니다.
Xcode 6 베타 3에서 동작이 변경되었습니다.어레이는 더 이상 참조 유형이 아니며 Copy-on-Write 메커니즘이 있습니다.즉, 어레이의 내용을 다른 변수에서 변경하면 어레이가 복사되고 하나의 복사본만 변경됩니다.
오래된 답변:
다른 사람들이 지적한 바와 같이 Swift는 가능하면 단일 인덱스의 값을 동시에 변경하는 등 어레이 복사를 피하려고 합니다.
변수가 다른는, 「」를 호출할 수 .unshare
1개만 한 됩니다.참조가 아직1개만 없는 한 어레이가 복사됩니다. '어디로 할까요?'라고도 있죠.copy
method: 항상 복사를 만들지만 동일한 배열에 다른 변수가 유지되지 않도록 하려면 공유 해제를 권장합니다.
var a = [1, 2, 3]
var b = a
b.unshare()
a[1] = 42
a // [1, 42, 3]
b // [1, 2, 3]
은 매우 합니다.Array.Resize
메서드를 지정합니다.NET.일이 있는지 하기 위해서는 NET의 이 될 입니다. 무슨 일이 일어나고 있는지 이해하려면 , 이력을 보는 것이 도움이 될 수 있습니다..
C 및 Swift.C, C++, Java, C# "Swift" 입니다.
C에서 구조는 변수의 집계에 지나지 않습니다.의 적용.
구조 유형의 변수에 대해 구조 내에 저장된 변수에 액세스합니다.오브젝트에 대한 포인터는 변수의 집약을 유지하는 것이 아니라 변수를 식별합니다.구조체를 식별하는 포인터가 있는 경우->
연산자는 포인터로 식별되는 구조 내에 저장된 변수에 액세스하기 위해 사용할 수 있습니다.
C++에서는 구조 및 클래스는 변수를 집약할 뿐만 아니라 변수에 코드를 부가할 수도 있습니다.「」를 사용합니다..
메서드를 호출하려면 변수에 대해 해당 메서드가 변수 자체의 내용에 따라 행동하도록 요청해야 합니다.->
오브젝트를 식별하는 변수에서는 변수에 의해 식별된 오브젝트에 대해 그 메서드가 동작하도록 요구합니다.
Java에서는 모든 커스텀 변수 유형이 단순히 객체를 식별하며 변수에 대해 메서드를 호출하면 변수에 의해 식별되는 객체가 메서드에 표시됩니다.변수는 어떠한 종류의 복합 데이터 유형도 직접 보유할 수 없으며 메서드가 호출되는 변수에 액세스할 수 있는 수단도 없습니다.이러한 제한은 의미적으로는 제한적이지만 실행 시간을 대폭 간소화하고 바이트 코드 검증을 용이하게 합니다. 이러한 단순화는 시장이 이러한 문제에 민감했던 시기에 Java의 리소스 오버헤드를 줄여 시장에서 Java의 관심을 끄는 데 도움이 되었습니다., ,, 이, 령, 에 상당하는 ..
C++로 하다는 ""를 사용할 수 ,->
및 와 같은 으로 작성자는 C++의 단일 를 사용하도록 했습니다..
다른 목적으로는 필요없었기 때문입니다.
C# 및 c 。NET 언어, 변수는 객체를 식별하거나 복합 데이터 유형을 직접 보유할 수 있습니다.에서 사용하는 , 「」는 다음과 같이 됩니다..
변수의 내용에 따라 작용합니다. 참조 유형의 변수에 사용되는 경우,.
이 오브젝트에 의해 식별된 오브젝트에 대해 동작합니다.어떤 종류의 작업에서는 의미적 구분이 특별히 중요한 것은 아니지만 다른 작업에서는 의미적 구분이 중요합니다.가장 문제가 되는 상황은 호출되는 변수를 수정하는 복합 데이터 유형의 메서드가 읽기 전용 변수에 호출되는 경우입니다.읽기 전용 값 또는 변수에 대해 메서드를 호출하려고 하면 컴파일러는 일반적으로 변수를 복사하고 메서드가 그에 따라 작동하도록 하고 변수를 폐기합니다.이것은 일반적으로 변수를 읽기만 하는 메서드에서는 안전하지만 변수를 쓰는 메서드에서는 안전하지 않습니다.유감스럽게도 .dos에는 이러한 대체를 사용하여 어떤 방법을 안전하게 사용할 수 있는지, 어떤 방법을 사용할 수 없는지를 나타내는 수단이 아직 없습니다.
Swift에서는 Aggregate의 메서드가 호출되는 변수를 수정할 것인지 여부를 명시적으로 나타낼 수 있습니다.또한 컴파일러는 변수의 임시 복사본을 변환하는 대신 읽기 전용 변수에 대한 메서드의 사용을 금지합니다. 때문에 이 구별을 .
에서는 .보다 swift에서를 호출하는 것이 합니다. 입니다. 행하게 、 같같같같같.
토큰은 혼동의 가능성이 남아 있는 변수로 식별되는 외부 객체에 작용하기 위해 사용됩니다.
C# Swift의 C#/Swift를 사용하는 로 이러한 을 소급하여 할 수 ..
★★★★★★★★★★★★★★★★★」->
C++는 C++로 동작합니다.에는, 「」를 사용할 수 ..
호출된 변수에 따라 행동할 수 있습니다.->
값(복합 재료용) 또는 이에 의해 식별된 것(기준 유형용)에 따라 작용한다.그러나 어느 언어도 그렇게 설계되지 않았다.
에서는 변수를 를 C#으로 입니다.ref
메서드에 대한 매개 변수. 해서 래서전전 thus thus thus thus thus thus thus thus라고 합니다.Array.Resize(ref someArray, 23);
때someArray
, 이 20개의 요소를 발생시키는 것을 .someArray
기존 어레이에 영향을 주지 않고 23개 요소의 새로운 어레이를 식별합니다.「 」의 ref
는 메서드가 호출되는 변수를 변경하는 것을 상정하고 있음을 명확히 하고 있습니다.하지 않고 할 수 주소는 Swift를 사용하여 할 수 있습니다.Swift 는 Swift address를 합니다..
구문을 사용합니다.단점은 변수에 어떤 방법이 작용하고 값에 어떤 방법이 작용하는지 명확하지 않다는 것입니다.
먼저 상수를 변수로 대체하는 것이 더 의미가 있습니다.
a[i] = 42 // (1)
e[i..j] = [4, 5] // (2)
줄에서는 .a
특히 메모리 할당을 할 필요가 없습니다.「 」의 값에 ,i
작업입니다 걸 a
는 포인터이며, 상수 포인터일 수 있습니다.
두 번째 줄은 훨씬 더 복잡할 수 있습니다.의 값에 .i
★★★★★★★★★★★★★★★★★」j
을 사용법라고 e
는 배열의 내용을 가리키는 포인터입니다.상수 포인터로 간주할 수 없게 됩니다.새로운 메모리 블록을 할당하고 오래된 메모리 블록에서 새로운 메모리 블록으로 데이터를 복사하여 포인터를 변경해야 할 수 있습니다.
언어 디자이너들은 (1)을 가능한 한 가볍게 유지하려고 노력한 것 같습니다.(2)는 어쨌든 복사를 수반하는 경우가 있기 때문에, 항상 복사를 한 것처럼 동작하는 솔루션에 의지하고 있습니다.
이것은 복잡하지만, 예를 들어 "(2) i와 j가 컴파일 시간 상수이고 컴파일러가 e의 크기가 변하지 않을 것이라고 추론할 수 있다면, 우리는 복사하지 않는다"와 같은 특별한 경우로 인해 더 복잡해지지 않은 것은 기쁩니다.
마지막으로 스위프트 언어의 디자인 원리에 대한 이해를 바탕으로 일반적인 규칙은 다음과 같습니다.
- 사용( 「」 「」)
let
디폴트에서는, 항상 모든 장소에 배치되어 있기 때문에, 큰 놀라움은 없습니다. - 사용( 「 」 )
var
반드시 필요한 경우에만, 그리고 이러한 경우 주의해야 합니다.이치[여기서: 모든 상황은 아니지만 어레이의 이상한 암묵적인 복사]
내가 찾은 건작업에 어레이 길이가 변경될 가능성이 있는 경우에만 어레이는 참조된 어레이의 가변 복사본이 됩니다.마지막 예에서는f[0..2]
많은 작업을 인덱싱하면 작업 길이가 변경될 수 있으므로(복제가 허용되지 않을 수 있음) 복사됩니다.
var e = [1, 2, 3]
var f = e
e[0..2] = [4, 5]
e // 4,5,3
f // 1,2,3
var e1 = [1, 2, 3]
var f1 = e1
e1[0] = 4
e1[1] = 5
e1 // - 4,5,3
f1 // - 4,5,3
델파이의 문자열과 배열은 완전히 같은 "기능"을 가지고 있었습니다.실장 상황을 보면 이해가 됩니다.
각 변수는 동적 메모리에 대한 포인터입니다.이 메모리에는 참조 카운트와 어레이의 데이터가 차례로 포함됩니다.따라서 어레이 전체를 복사하거나 포인터를 변경하지 않고도 어레이의 값을 쉽게 변경할 수 있습니다.어레이 크기를 조정하려면 메모리를 더 할당해야 합니다.이 경우 현재 변수는 새로 할당된 메모리를 가리킵니다.그러나 원래 어레이를 가리킨 다른 모든 변수를 쉽게 추적할 수 없기 때문에 그대로 둡니다.
물론 좀 더 일관된 구현을 하는 것은 어렵지 않습니다.모든 변수에 크기를 표시하려면 다음을 수행합니다.각 변수는 동적 메모리에 저장된 컨테이너에 대한 포인터입니다.컨테이너에는 참조 수와 실제 배열 데이터에 대한 포인터라는 정확히 두 가지가 들어 있습니다.어레이 데이터는 별도의 동적 메모리 블록에 저장됩니다.어레이 데이터에 대한 포인터는 1개뿐이므로 쉽게 크기를 조정할 수 있으며 모든 변수에 변경이 표시됩니다.
많은 Swift 얼리어답터들이 이 오류 발생 가능성이 높은 어레이 시멘틱스에 대해 불만을 제기하고 있으며 Chris Ratner는 어레이 시멘틱스가 완전한 가치 시멘틱스를 제공하도록 수정되었다고 쓰고 있습니다(계정을 가지고 있는 사용자를 위한 Apple Developer 링크).이것이 정확히 무엇을 의미하는지 알아보려면 적어도 다음 베타판을 기다려야 합니다.
여기에는 .copy()를 사용합니다.
var a = [1, 2, 3]
var b = a.copy()
a[1] = 42
이후 Swift 버전에서 어레이 동작에 변화가 있었습니까?예를 들어 보겠습니다.
var a = [1, 2, 3]
var b = a
a[1] = 42
a
b
결과는 [1, 42, 3]과 [1, 2, 3]입니다.
언급URL : https://stackoverflow.com/questions/24081009/is-there-a-reason-that-swift-array-assignment-is-inconsistent-neither-a-referen
'programing' 카테고리의 다른 글
sql 기본 키 및 인덱스 (0) | 2023.04.17 |
---|---|
c# 코드로 Data Template를 빌드하려면 어떻게 해야 하나요? (0) | 2023.04.17 |
셸 스크립트의 YYY-MM-DD 형식 날짜 (0) | 2023.04.17 |
bash에서 단일 명령을 사용하여 셸 변수에 기본값 할당 (0) | 2023.04.17 |
코드 배후에 있는 콜명령어 (0) | 2023.04.17 |