Swift에서 유형이 지정된 배열을 어떻게 확장 할 수 있습니까?
사용자 정의 기능 유틸리티를 사용하여 Swift Array<T>
또는 T[]
유형을 확장하려면 어떻게 해야합니까?
Swift의 API 문서를 살펴보면 Array 메소드가의 확장 인 것을 알 수 있습니다 T[]
.
extension T[] : ArrayType {
//...
init()
var count: Int { get }
var capacity: Int { get }
var isEmpty: Bool { get }
func copy() -> T[]
}
동일한 소스를 복사하여 붙여넣고 다음과 같은 변형을 시도 할 때 :
extension T[] : ArrayType {
func foo(){}
}
extension T[] {
func foo(){}
}
오류로 인해 빌드에 실패합니다.
공칭 유형
T[]
은 확장 할 수 없습니다
전체 유형 정의를 사용하면 다음과 같이 실패합니다 Use of undefined type 'T'
.
extension Array<T> {
func foo(){}
}
그리고 그것은 또한 실패 Array<T : Any>
하고 Array<String>
.
Curiously Swift를 사용하면 다음을 사용하여 유형이 지정되지 않은 배열을 확장 할 수 있습니다.
extension Array {
func each(fn: (Any) -> ()) {
for i in self {
fn(i)
}
}
}
내가 전화 할 수있는 것은 :
[1,2,3].each(println)
그러나 Swift의 내장 필터를 다음 과 같이 대체 하는 방법과 같이 유형이 메소드를 통과 할 때 유형이 손실 된 것처럼 보이기 때문에 적절한 일반 유형 확장자를 작성할 수 없습니다 .
extension Array {
func find<T>(fn: (T) -> Bool) -> T[] {
var to = T[]()
for x in self {
let t = x as T
if fn(t) {
to += t
}
}
return to
}
}
그러나 컴파일러는 다음을 사용하여 확장을 호출 할 수있는 유형화되지 않은 것으로 취급합니다.
["A","B","C"].find { $0 > "A" }
그리고 디버거를 사용하여 단계별로 입력하면 유형이 표시 Swift.String
되지만 String
먼저 캐스팅하지 않고 문자열처럼 액세스하려고하면 빌드 오류입니다 .
["A","B","C"].find { ($0 as String).compare("A") > 0 }
누구나 기본 제공 확장 기능과 같은 유형의 확장 메서드를 만드는 적절한 방법이 무엇인지 알고 있습니까?
클래스 를 사용하여 유형이 지정된 배열을 확장 하면 다음이 작동합니다 (Swift 2.2 ). 예를 들어 형식화 된 배열을 정렬하면 다음과 같습니다.
class HighScoreEntry {
let score:Int
}
extension Array where Element:HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}
이 작업을 수행하려고 구조체 또는 typealias 오류를 줄 것이다 :
Type 'Element' constrained to a non-protocol type 'HighScoreEntry'
업데이트 :
비 클래스로 형식화 된 배열을 확장하려면 다음 방법을 사용하십시오.
typealias HighScoreEntry = (Int)
extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}
에서 스위프트 3 일부 유형은 이름이 변경되었습니다 :
extension Sequence where Iterator.Element == HighScoreEntry
{
// ...
}
잠시 다른 시도를 한 후에 솔루션은 <T>
다음과 같이 서명에서 서명 을 제거하는 것 같습니다 .
extension Array {
func find(fn: (T) -> Bool) -> [T] {
var to = [T]()
for x in self {
let t = x as T;
if fn(t) {
to += t
}
}
return to
}
}
빌드 오류없이 의도 한대로 작동합니다.
["A","B","C"].find { $0.compare("A") > 0 }
비슷한 문제가있었습니다-일반적인 배열을 swap () 메소드로 확장하고 싶었습니다.이 메소드는 배열과 동일한 유형의 인수를 취해야했습니다. 그러나 제네릭 형식을 어떻게 지정합니까? 시행 착오에 의해 아래에서 작동한다는 것을 알았습니다.
extension Array {
mutating func swap(x:[Element]) {
self.removeAll()
self.appendContentsOf(x)
}
}
그 핵심은 '요소'라는 단어였습니다. 이 유형을 어디에도 정의하지 않았으며 배열 확장의 컨텍스트 내에 자동으로 존재하는 것으로 보이며 배열 요소의 유형이 무엇이든 참조하십시오.
나는 무슨 일이 일어나고 있는지 100 % 확신하지 못하지만 아마도 'Element'가 배열의 관련 유형이기 때문일 것입니다 ( https://developer.apple.com/library/ios/documentation의 'Associated Types' 참조) /Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID189 )
그러나 배열 구조 참조 ( https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Array_Structure/index.html#//apple_ref/swift 에서이 참조를 볼 수 없습니다. / struct / s : Sa ) ... 그래서 나는 여전히 조금 확실하지 않습니다.
모든 유형을 확장 하십시오 .
extension Array where Element: Comparable {
// ...
}
일부 유형을 확장하십시오 .
extension Array where Element: Comparable & Hashable {
// ...
}
특정 유형을 확장하십시오 .
extension Array where Element == Int {
// ...
}
Swift 2.2 사용 : 문자열 배열에서 중복을 제거하려고 할 때 비슷한 문제가 발생했습니다. 내가 원하는 것을하는 Array 클래스에 확장을 추가 할 수있었습니다.
extension Array where Element: Hashable {
/**
* Remove duplicate elements from an array
*
* - returns: A new array without duplicates
*/
func removeDuplicates() -> [Element] {
var result: [Element] = []
for value in self {
if !result.contains(value) {
result.append(value)
}
}
return result
}
/**
* Remove duplicate elements from an array
*/
mutating func removeDuplicatesInPlace() {
var result: [Element] = []
for value in self {
if !result.contains(value) {
result.append(value)
}
}
self = result
}
}
이 두 메소드를 Array 클래스에 추가하면 배열에서 두 메소드 중 하나를 호출하고 중복을 성공적으로 제거 할 수 있습니다. 배열의 요소는 Hashable 프로토콜을 준수해야합니다. 이제 나는 이것을 할 수 있습니다 :
var dupes = ["one", "two", "two", "three"]
let deDuped = dupes.removeDuplicates()
dupes.removeDuplicatesInPlace()
// result: ["one", "two", "three"]
이 github repo https://github.com/ankurp/Cent 에서 배열 및 클래스의 빌드 유형 확장에 대해 배우려면 https://github.com/ankurp/Cent
Xcode 6.1부터 배열을 확장하는 구문은 다음과 같습니다.
extension Array {
func at(indexes: Int...) -> [Element] {
... // You code goes herer
}
}
Swift 2 표준 라이브러리 헤더를 살펴 보았습니다. 여기 필터 기능의 프로토 타입이 있습니다.
extension CollectionType {
func filter(@noescape includeElement: (Self.Generator.Element) -> Bool) -> [Self.Generator.Element]
}
Array의 확장이 아니라 CollectionType의 확장이므로 동일한 메소드가 다른 컬렉션 유형에 적용됩니다. @noescape는 전달 된 블록이 필터 기능의 범위를 벗어나지 않아 일부 최적화가 가능함을 의미합니다. 자본 S를 가진 자아는 우리가 확장하는 계급입니다. Self.Generator는 컬렉션의 개체를 반복하는 반복자이며 Self.Generator.Element는 개체의 유형입니다 (예 : 배열 [Int?]). Self.Generator.Element는 Int?입니다.
이 필터 방법은 모든 CollectionType에 적용 할 수 있으며 컬렉션의 요소를 가져 와서 Bool을 반환하는 필터 블록이 필요하며 원래 유형의 배열을 반환합니다. 이것을 합치면 다음과 같은 유용한 방법이 있습니다. 콜렉션 요소를 선택적 값에 매핑하는 블록을 가져 와서 맵과 필터를 결합하고 nil이 아닌 선택적 값의 배열을 반환합니다.
extension CollectionType {
func mapfilter<T>(@noescape transform: (Self.Generator.Element) -> T?) -> [T] {
var result: [T] = []
for x in self {
if let t = transform (x) {
result.append (t)
}
}
return result
}
}
import Foundation
extension Array {
var randomItem: Element? {
let idx = Int(arc4random_uniform(UInt32(self.count)))
return self.isEmpty ? nil : self[idx]
}
}
( 스위프트 2.x )
또한 일반적인 형식 메서드에 대해 파란색 -rpint를 포함하는 프로토콜, 예를 들어 프로토콜과 같은 일부 형식 제약 조건을 따르는 모든 일반 배열 요소에 대한 사용자 지정 기능 유틸리티를 포함하는 프로토콜에 맞게 배열을 확장 할 수 있습니다 MyTypes
. 이 접근 방식을 사용하는 이점은 일반 배열 인수를 사용하여 함수를 작성할 수 있다는 것입니다. 이러한 배열 인수는 프로토콜과 같은 사용자 정의 함수 유틸리티 프로토콜을 준수해야한다는 제약이 있습니다 MyFunctionalUtils
.
배열 요소를로 제한하여 유형을 지정하여 암시 적 으로이 동작을 얻을 수 있습니다 MyTypes
. 또는 아래 설명 된 방법에서 볼 수 있듯이 일반 배열 함수 헤더에 입력 배열을 직접 표시합니다. 을 준수합니다 MyFunctionalUtils
.
MyTypes
타입 제약으로 사용 하기 위한 프로토콜 로 시작합니다 . 이 프로토콜을 사용하여 제네릭에 맞추려는 유형을 확장하십시오 (아래 예는 기본 유형 Int
및 Double
사용자 정의 유형을 확장 합니다 MyCustomType
)
/* Used as type constraint for Generator.Element */
protocol MyTypes {
var intValue: Int { get }
init(_ value: Int)
func *(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : MyTypes { var intValue: Int { return self } }
extension Double : MyTypes { var intValue: Int { return Int(self) } }
// ...
/* Custom type conforming to MyTypes type constraint */
struct MyCustomType : MyTypes {
var myInt : Int? = 0
var intValue: Int {
return myInt ?? 0
}
init(_ value: Int) {
myInt = value
}
}
func *(lhs: MyCustomType, rhs: MyCustomType) -> MyCustomType {
return MyCustomType(lhs.intValue * rhs.intValue)
}
func +=(inout lhs: MyCustomType, rhs: MyCustomType) {
lhs.myInt = (lhs.myInt ?? 0) + (rhs.myInt ?? 0)
}
프로토콜 MyFunctionalUtils
(추가적인 일반적인 배열 함수 유틸리티의 청사진을 잡고 있음)과 그 후 Array by MyFunctionalUtils
; 블루 프린트 방식의 구현 :
/* Protocol holding our function utilities, to be used as extension
o Array: blueprints for utility methods where Generator.Element
is constrained to MyTypes */
protocol MyFunctionalUtils {
func foo<T: MyTypes>(a: [T]) -> Int?
// ...
}
/* Extend array by protocol MyFunctionalUtils and implement blue-prints
therein for conformance */
extension Array : MyFunctionalUtils {
func foo<T: MyTypes>(a: [T]) -> Int? {
/* [T] is Self? proceed, otherwise return nil */
if let b = self.first {
if b is T && self.count == a.count {
var myMultSum: T = T(0)
for (i, sElem) in self.enumerate() {
myMultSum += (sElem as! T) * a[i]
}
return myMultSum.intValue
}
}
return nil
}
}
마지막으로, 다음과 같은 경우에 각각 일반 배열을 취하는 함수를 보여주는 테스트와 두 가지 예
배열 매개 변수를 'MyTypes'(함수 )로 제한하는 유형을 통해 배열 매개 변수가 프로토콜 'MyFunctionalUtils'를 준수한다는 암시 적 주장을 표시
bar1
합니다.Showing explicitly that the array parameters conform to protocol 'MyFunctionalUtils' (function
bar2
).
The test and examples follows:
/* Tests & examples */
let arr1d : [Double] = [1.0, 2.0, 3.0]
let arr2d : [Double] = [-3.0, -2.0, 1.0]
let arr1my : [MyCustomType] = [MyCustomType(1), MyCustomType(2), MyCustomType(3)]
let arr2my : [MyCustomType] = [MyCustomType(-3), MyCustomType(-2), MyCustomType(1)]
/* constrain array elements to MyTypes, hence _implicitly_ constraining
array parameters to protocol MyFunctionalUtils. However, this
conformance is not apparent just by looking at the function signature... */
func bar1<U: MyTypes> (arr1: [U], _ arr2: [U]) -> Int? {
return arr1.foo(arr2)
}
let myInt1d = bar1(arr1d, arr2d) // -4, OK
let myInt1my = bar1(arr1my, arr2my) // -4, OK
/* constrain the array itself to protocol MyFunctionalUtils; here, we
see directly in the function signature that conformance to
MyFunctionalUtils is given for valid array parameters */
func bar2<T: MyTypes, U: protocol<MyFunctionalUtils, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {
// OK, type U behaves as array type with elements T (=MyTypes)
var a = arr1
var b = arr2
a.append(T(2)) // add 2*7 to multsum
b.append(T(7))
return a.foo(Array(b))
/* Ok! */
}
let myInt2d = bar2(arr1d, arr2d) // 10, OK
let myInt2my = bar2(arr1my, arr2my) // 10, OK
import Foundation
extension Array {
func calculateMean() -> Double {
// is this an array of Doubles?
if self.first is Double {
// cast from "generic" array to typed array of Doubles
let doubleArray = self.map { $0 as! Double }
// use Swift "reduce" function to add all values together
let total = doubleArray.reduce(0.0, combine: {$0 + $1})
let meanAvg = total / Double(self.count)
return meanAvg
} else {
return Double.NaN
}
}
func calculateMedian() -> Double {
// is this an array of Doubles?
if self.first is Double {
// cast from "generic" array to typed array of Doubles
var doubleArray = self.map { $0 as! Double }
// sort the array
doubleArray.sort( {$0 < $1} )
var medianAvg : Double
if doubleArray.count % 2 == 0 {
// if even number of elements - then mean average the middle two elements
var halfway = doubleArray.count / 2
medianAvg = (doubleArray[halfway] + doubleArray[halfway - 1]) / 2
} else {
// odd number of elements - then just use the middle element
medianAvg = doubleArray[doubleArray.count / 2 ]
}
return medianAvg
} else {
return Double.NaN
}
}
}
참고URL : https://stackoverflow.com/questions/24027116/how-can-i-extend-typed-arrays-in-swift
'Programming' 카테고리의 다른 글
요소의 부모 div 얻기 (0) | 2020.05.15 |
---|---|
Python에서 Pandas와 NumPy + SciPy의 차이점은 무엇입니까? (0) | 2020.05.15 |
postgresql에서 DB에 대한 사용자를 만드는 방법은 무엇입니까? (0) | 2020.05.15 |
레일 : dependent => : destroy VS : dependent => : delete_all (0) | 2020.05.15 |
특정 시점에 할당 된 문제를 찾는 방법은 무엇입니까? (0) | 2020.05.15 |