신속하고 돌연변이적인 구조
Swift의 가치 유형을 변형시키는 것과 관련하여 제가 완전히 이해하지 못하는 부분이 있습니다.
"스위프트 프로그래밍 언어" 아이북은 다음과 같이 말합니다.기본적으로 값 형식의 속성은 인스턴스 메서드 내에서 수정할 수 없습니다.
는 그리고이가하기위해우방수선있다습니언법할리을는것능게을하▁▁the▁methods▁and다▁can있▁declare니습수▁possible로 메소드를 선언할 수 있습니다.mutating키워드를 구조체 및 열거형 내부에 입력합니다.
제가 완전히 이해하지 못하는 것은 다음과 같습니다.구조체 외부에서 변수를 변경할 수 있지만 고유한 방법에서는 변수를 변경할 수 없습니다.이것은 객체 지향 언어에서와 같이 일반적으로 변수를 캡슐화하여 내부에서만 변경할 수 있도록 하려는 저에게는 직관에 반하는 것으로 보입니다.구조물의 경우에는 그 반대인 것 같습니다.자세한 내용은 코드 스니펫을 참조하십시오.
struct Point {
var x = 0, y = 0
mutating func moveToX(x: Int, andY y:Int) { //Needs to be a mutating method in order to work
self.x = x
self.y = y
}
}
var p = Point(x: 1, y: 2)
p.x = 3 //Works from outside the struct!
p.moveToX(5, andY: 5)
구조체가 자신의 맥락 안에서 내용을 변경할 수 없는 반면, 내용은 다른 곳에서 쉽게 변경할 수 있는 이유를 아는 사람이 있습니까?
변동성 특성은 유형이 아닌 저장소(상수 또는 변수)에 표시됩니다.구조에는 두 가지 모드가 있다고 생각할 수 있습니다. 가변 모드와 불변 모드입니다.구조 값을 불변 스토리지에 할당하는 경우(이를 불변 스토리지라고 함)let또는 Swift에서 상수) 값이 불변 모드가 되고 값의 상태를 변경할 수 없습니다.(변종 방법 호출 포함)
저장소에 는 그것을 값이가이스에할경당된우지리토가킴리변를이▁it▁(경▁if▁call()우we▁is▁the킴가▁a▁storage▁value리할able▁to당▁assigned)var또는 Swift에서 변수)의 상태를 자유롭게 수정할 수 있으며, 돌연변이 메서드 호출이 허용됩니다.
또한 클래스에는 이 불변/변종 모드가 없습니다.IMO, 클래스는 일반적으로 참조 가능한 엔티티를 나타내는 데 사용되기 때문입니다.그리고 참조 가능한 엔티티는 일반적으로 가변적입니다. 적절한 성능으로 엔티티의 참조 그래프를 불변의 방식으로 만들고 관리하기가 매우 어렵기 때문입니다.나중에 이 기능을 추가할 수 있지만 적어도 지금은 추가할 수 없습니다.
Objective-C 프로그래머에게 가변/불변 개념은 매우 친숙합니다.Objective-C에서는 각 개념에 대해 두 개의 클래스가 있었지만 Swift에서는 하나의 구조로 이를 수행할 수 있습니다.일의 절반.
C/C++ 프로그래머들에게 이것은 또한 매우 친숙한 개념입니다.바로 이것입니다.constC/C++에서 수행합니다.
또한 불변의 가치는 매우 잘 최적화될 수 있습니다.이론적으로 스위프트 컴파일러(또는 LLVM)는 다음과 같이 전달된 값에 대해 복사-엘리젼을 수행할 수 있습니다.letC++에서처럼.불변의 구조를 현명하게 사용한다면, 그것은 refcounted 클래스를 능가할 것입니다.
갱신하다
@Joseph가 이것이 이유를 제공하지 않는다고 주장했듯이, 저는 조금 더 덧붙입니다.
구조에는 두 가지 방법이 있습니다. 단순한 방법과 돌연변이 방법입니다.일반 방법은 불변(또는 비변종)을 의미합니다.이 분리는 불변의 의미론을 지원하기 위해서만 존재합니다.불변 모드의 개체는 상태를 전혀 변경할 수 없습니다.
그렇다면 불변의 방법은 이러한 의미 불변성을 보장해야 합니다.즉, 내부 가치를 변경해서는 안 됩니다.따라서 컴파일러는 불변의 방법으로 상태 변화를 허용하지 않습니다.반대로, 돌연변이 방법은 상태를 자유롭게 수정할 수 있습니다.
그리고 왜 불변이 기본값인지에 대한 질문이 있을 수 있습니다.그것은 가치가 돌연변이를 일으키는 미래의 상태를 예측하는 것이 매우 어렵기 때문입니다. 그리고 그것은 보통 두통과 버그의 주요 원인이 됩니다.많은 사람들이 해결책이 변형 가능한 것을 피하는 것이라는 데 동의했고, C/C++ 패밀리 언어와 그 파생어에서 수십 년 동안 기본적으로 불변이 상위 목록에 있었습니다.
자세한 내용은 순수한 기능 스타일을 참조하십시오.어쨌든, 불변의 것들은 몇 가지 약점이 있기 때문에 우리는 여전히 불변의 것들이 필요하고, 그것들에 대한 논의는 주제에서 벗어난 것 같습니다.
주의: 비전문가의 조건이 앞에 있습니다.
이 설명은 가장 핵심적인 코드 수준에서 엄격하게 정확하지 않습니다.하지만 스위프트에서 실제로 일하는 사람이 검토했고 그는 기본적인 설명으로 충분하다고 말했습니다.
그래서 저는 "왜"라는 질문에 간단하고 직접적으로 대답하려고 노력하고 싶습니다.
정확하게 말하자면, 왜 우리는 구조 함수를 어떠한 수정 키워드 없이 구조 매개변수를 변경할 수 있는 것으로 표시해야 합니까?
큰 그림은 스위프트를 신속하게 유지하는 철학과 많은 관련이 있습니다.
실제 물리적 주소를 관리하는 문제라고 생각할 수 있습니다.주소를 변경할 때, 현재 주소를 가지고 있는 사람이 많을 경우, 이사했음을 모두에게 알려야 합니다.하지만 현재 주소를 아는 사람이 없으면 원하는 곳으로 이동할 수 있으며 아무도 알 필요가 없습니다.
이런 상황에서 스위프트는 일종의 우체국과 같습니다.연락처가 많은 사람들이 많이 돌아다닌다면, 그것은 정말 높은 비용이 많이 듭니다.이 모든 알림을 처리하려면 많은 직원에게 비용을 지불해야 하며, 이 과정에는 많은 시간과 노력이 소요됩니다.그렇기 때문에 스위프트의 이상적인 상태는 마을의 모든 사람들이 가능한 한 연락처를 적게 갖는 것입니다.그러면 주소 변경을 처리하는 데 큰 인력이 필요하지 않고 다른 모든 작업을 더 빠르고 더 잘 수행할 수 있습니다.
이것이 바로 Swift-folks가 가치 유형 대 참조 유형에 대해 모두 열광하는 이유이기도 합니다.기본적으로 참조 유형은 "연락처"를 곳곳에 보관하며, 가치 유형은 일반적으로 두 개 이상의 연락처가 필요하지 않습니다.값 유형은 "Swift"-er입니다.
이제 다시 작은 그림으로 돌아갑니다.structs구조체는 Swift에서 매우 중요합니다. 왜냐하면 객체가 할 수 있는 대부분의 일을 할 수 있기 때문입니다. 그러나 그것들은 가치 유형입니다.
이제 해서 상상해보도록 하겠습니다.misterStruct에 someObjectVille비유가 여기서 약간 혼란스럽지만, 저는 여전히 도움이 된다고 생각합니다.
변수변모면려에서 하는 것입니다.struct를 들어 령가misterStruct녹색 머리를 가졌고, 파란색 머리로 바꾸라는 명령을 받았습니다.제가 말씀드린 것처럼 비유가 이상해지지만, 어떤 종류의 일이 일어나는 것은 변화하는 대신입니다.misterStruct머리카락, 늙은 사람이 이사를 가고 파란 머리를 가진 새로운 사람이 이사를 오고, 그 새로운 사람은 스스로를 부르기 시작합니다.misterStruct누구도 주소 변경 통지를 받을 필요는 없지만, 만약 누군가가 그 주소를 본다면, 그들은 파란 머리를 가진 남자를 볼 것입니다.
이제 함수를 호출할 때 어떤 일이 일어나는지 모델링해 보겠습니다.struct이경에는우, 치마치,와 .misterStruct다음과 같은 주문을 받습니다.changeYourHairBlue()그래서 우체국은 지시를 전달합니다.misterStruct"머리를 파란색으로 바꾸고 끝나면 말해주세요."
그가 이전과 , 때 한 , 을 하고 있는지, 무엇을 하고 있는지, 무엇을 하고 있는지,misterStruct자기 집에서 나와서 파란 머리를 가진 새로운 사람을 부를 것입니다.하지만 그게 문제입니다.
주문은 "파란색으로 머리를 바꾸고 끝나면 말해주세요"였지만, 그 주문을 받은 사람은 녹색 남자입니다.파란색 직원이 이사 온 후에도 "작업 완료" 알림이 다시 전송되어야 합니다.하지만 그 파란 남자는 그것에 대해 아무것도 모릅니다.
[이 비유를 정말로 놀라운 것으로 하자면, 기술적으로 녹색 머리의 남자에게 일어난 일은 그가 이사를 간 후에, 그는 즉시 자살했다는 것입니다.따라서 작업이 완료되었음을 아무에게도 알릴 수 없습니다!]
이 문제를 피하기 위해서는 이런 경우에만 스위프트가 그 주소지의 집으로 직접 들어가서 현재 거주자의 머리카락을 실제로 바꿔야 합니다.그것은 단지 새로운 사람을 보내는 것과는 완전히 다른 과정입니다.
그래서 스위프트는 우리가 그것을 사용하기를 원하는 것입니다.mutating키워드!
최종 결과는 구조를 참조해야 하는 모든 것에서 동일하게 보입니다: 그 집의 거주자는 현재 파란 머리를 가지고 있습니다.하지만 그것을 달성하기 위한 과정은 실제로 완전히 다릅니다.같은 일을 하고 있는 것처럼 보이지만, 아주 다른 일을 하고 있습니다.이것은 스위프트 구조가 일반적으로 절대 하지 않는 일을 하는 것입니다.
서투른 도움을 , 가 변형을 .struct그렇지 않으면, 그 자체로, 모든 단일 구조 함수에 대해, 우리는 연민을 가지고 사용하도록 요청받습니다.mutating 키워드
본질적으로 스위프트가 신속하게 활동할 수 있도록 돕기 위해서는 우리 모두가 자신의 역할을 다해야 합니다.:)
구조체는 필드 집합입니다. 특정 구조체 인스턴스가 변경 가능하면 필드가 변경 가능하고 인스턴스가 변경 불가능하면 필드가 변경 불가능합니다.따라서 구조 유형은 특정 인스턴스의 필드가 변경 가능하거나 변경 불가능할 수 있는 가능성에 대비해야 합니다.
구조 메소드가 기본 구조체의 필드를 변형시키려면 해당 필드가 변형되어야 합니다.기본 구조체의 필드를 변환하는 메서드가 불변 구조체에서 호출되면 불변 필드를 변환하려고 합니다.그것으로부터 좋은 것은 아무것도 나올 수 없기 때문에, 그러한 발동은 금지될 필요가 있습니다.
이를 위해 Swift는 구조 방법을 두 가지 범주로 나눕니다. 즉, 기본 구조를 수정하는 것과 기본 구조를 수정하지 않는 것, 즉 가변 구조와 불변 인스턴스 모두에서 호출할 수 있어야 하는 것입니다.후자의 사용은 아마도 더 자주 사용되므로 기본값입니다.
그에 비해 .NET은 현재 (아직!) 구조를 수정하는 구조 방법과 그렇지 않은 구조 방법을 구분할 수 있는 수단을 제공하지 않습니다.대신, 불변 구조 인스턴스에서 구조 메소드를 호출하면 컴파일러가 구조 메소드의 변형 가능한 복사본을 만들고 메소드가 원하는 것을 수행하도록 하며 메소드가 완료되면 해당 복사본을 폐기합니다.이것은 메소드가 구조를 수정하든 아니든 간에 컴파일러가 구조를 복사하는 데 시간을 낭비하도록 하는 효과가 있습니다. 복사 작업을 추가하면 의미적으로 부정확한 코드가 의미적으로 정확한 코드로 변환되지 않을 것입니다.다른 방식으로 틀리는 것(구조를 수정하지만 시도된 변경 사항은 무시하는 코드).구조 메서드가 기본 구조를 수정할지 여부를 나타낼 수 있도록 허용하면 불필요한 복사 작업이 필요하지 않고 잘못된 사용 시도가 플래그가 지정되도록 할 수 있습니다.
스위프트 구조는 다음과 같은 상수로 인스턴스화할 수 있습니다.let 변수 ) 또는변수(via)var)
스위프트의 경우를 생각해 보십시오.Arraystruct(네, 구조입니다).
var petNames: [String] = ["Ruff", "Garfield", "Nemo"]
petNames.append("Harvey") // ["Ruff", "Garfield", "Nemo", "Harvey"]
let planetNames: [String] = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planetNames.append("Pluto") //Error, sorry Pluto. No can do
왜 부록은 행성 이름과 함께 작동하지 않았나요?는 append로 되어 있기 때문입니다.mutating키워드그리고 그 이후로planetNames다음을 사용하여 선언되었습니다.let이렇게 표시된 모든 방법은 금지됩니다.
당신의 예에서 컴파일러는 당신이 외부의 하나 이상의 속성에 할당함으로써 구조를 수정하고 있다고 말할 수 있습니다.init코드를 조금 변경하면 다음과 같은 것을 알 수 있습니다.x그리고.y항상 구조물 외부에서 액세스할 수 있는 것은 아닙니다.에 하십시오.let
let p = Point(x: 1, y: 2)
p.x = 3 //error
p.moveToX(5, andY: 5) //error
C++과 유사점을 생각해 보세요.스위프트 존재의 구조적 방법mutating/not-mutating이 C++이 경우와 합니다.const/const으로 표시된 방법constC++에서도 마찬가지로 구조를 변형시킬 수 없습니다.
구조체 외부에서 변수를 변경할 수 있지만 고유한 방법에서는 변수를 변경할 수 없습니다.
C++에서는 "구조 외부에서 변수를 변경"할 수도 있습니다. 단, 다음이 아닌 경우에만const구조 변수.만약 당신이 가지고 있다면.const할 수 var 의 것을 .const할 수 .마찬가지로 Swift에서는 구조 변수가 상수가 아닌 경우에만 구조물의 특성을 변경할 수 있습니다.구조 상수가 있는 경우 속성을 할당할 수 없으며 다음을 호출할 수도 없습니다.mutating방법.
제가 스위프트를 배우기 시작했을 때도 같은 것이 궁금했습니다. 그리고 이 각각의 답들은 아마도 약간의 통찰력을 추가하면서도 그 자체로 말이 많고 혼란스럽습니다.저는 당신의 질문에 대한 대답이 사실 매우 간단하다고 생각합니다.
구조체 내부에 정의된 돌연변이 방법은 미래에 생성될 자신의 모든 인스턴스를 수정할 수 있는 권한을 필요로 합니다.만약 그 인스턴스들 중 하나가 다음과 같은 불변 상수에 할당된다면?let어, 오.자신으로부터 사용자를 보호하기 위해(그리고 편집자와 컴파일러가 수행하려는 작업을 알게 하기 위해) 인스턴스 메소드에 이러한 권한을 부여하려면 명시적이어야 합니다.
반대로, 구조물 외부의 특성 설정은 해당 구조물의 알려진 인스턴스에서 작동합니다.상수에 할당된 경우 메서드 호출에 입력한 즉시 Xcode에서 이를 알려줍니다.
이것은 제가 Swift를 더 많이 사용하기 시작하면서 좋아하는 것 중 하나입니다. 입력할 때 오류에 대한 경고입니다.잘 알려지지 않은 자바스크립트 버그를 해결하는 것보다 훨씬 낫습니다!
SWIFT : Structs에서 돌연변이 기능 사용
스위프트 프로그래머는 Struct 메서드 내에서 속성을 수정할 수 없는 방식으로 Struct를 개발했습니다.예를 들어, 아래에 주어진 코드를 확인합니다.
struct City
{
var population : Int
func changePopulation(newpopulation : Int)
{
population = newpopulation //error: cannot modify property "popultion"
}
}
var mycity = City(population : 1000)
mycity.changePopulation(newpopulation : 2000)
위 코드를 실행할 때 Struct City의 부동산 인구에 새 값을 할당하려고 하기 때문에 오류가 발생합니다.기본적으로 Structs 특성은 고유한 메서드 내에서 변환할 수 없습니다.이것은 Apple Developers가 기본적으로 Structs가 정적인 특성을 갖도록 구축한 방법입니다.
어떻게 해결하죠?대안은 무엇입니까?
키워드 변환:
Struct 내부의 돌연변이로 함수를 선언하면 Structs의 속성을 변경할 수 있습니다.라인 번호 : 5, 상기 코드 중 이렇게 변경되는 것은
mutating changePopulation(newpopulation : Int)
이제 우리는 부동산 인구에 대한 새로운 인구의 가치를 방법의 범위 내에서 할당할 수 있습니다.
참고:
let mycity = City(1000)
mycity.changePopulation(newpopulation : 2000) //error: cannot modify property "popultion"
Struct 개체에 var 대신 let를 사용하면 속성 값을 변환할 수 없습니다. 또한 let 인스턴스를 사용하여 변환 함수를 호출하려고 하면 오류가 발생합니다.따라서 속성 값을 변경할 때마다 var를 사용하는 것이 좋습니다.
당신의 의견과 생각을 듣고 싶습니다….
빠른 돌연변이 구조
변종 하나 더
struct MyStruct {
var myVar = "myVar"
let myLet = "myLet"
}
func testMutateString() {
//given
let myStruct = MyStruct()
//Change var
//when
var myStructCopy = myStruct
myStructCopy.myVar = "myVar changed 1"
//then
XCTAssert(myStructCopy.myVar == "myVar changed 1")
//Change let
//when
withUnsafeMutableBytes(of: &myStructCopy) { bytes in
let offset = MemoryLayout.offset(of: \MyStruct.myLet)!
let rawPointerToValue = bytes.baseAddress! + offset
let pointerToValue = rawPointerToValue.assumingMemoryBound(to: String.self)
pointerToValue.pointee = "myLet changed"
}
//then
XCTAssert(myStructCopy.myLet == "myLet changed")
}
언급URL : https://stackoverflow.com/questions/24035648/swift-and-mutating-struct
'programing' 카테고리의 다른 글
| CSS를 사용하여 텍스트 삽입 (0) | 2023.08.28 |
|---|---|
| iOS 애플리케이션 스플래시 화면에 사용되는 크기는 무엇입니까? (0) | 2023.08.23 |
| JQuery 요소가 DOM에 있는지 확인하려면 어떻게 해야 합니까? (0) | 2023.08.23 |
| Spring @ContextXml에 적합한 위치를 지정하는 방법 (0) | 2023.08.23 |
| 명령이 성공적으로 실행되었는지 확인합니다. (0) | 2023.08.23 |