Что такое логика сравнения Slice в Swift

Вот код:

var arr1 = [1, 2, 3, 4]
var arr2 = [1, 2, 3, 4]

if arr1 == arr2 {
    println("Equal")
} else {
    println("Not Equal")
}
// console output: Equal

let slice1 = arr1[0..4]
let slice2 = arr2[0..4]

if slice1 == slice2 {
    println("Equal")
} else {
    println("Not Equal")
}
// console output: Equal

Это просто, но следующий код:

if arr1[0..4] == arr2[0..4] {
    println("Equal")
} else {
    println("Not Equal")
}
// console output: Not Equal

Почему результат "Не равен", а не "Равный"? Можно ли использовать оператор == для сравнения содержимого типа значений двух массивов или двух срезов? Если нет, то почему я мог получить исключенные результаты первых двух операторов if?

Ответ 1

Я считаю, что это ошибка компилятора, которая не вызывала правильную функцию перегрузки == для сравнения Slice при некоторых условиях.


это минимальный пример, который я вывел для создания проблемы

let s1 : Slice<Int> = Slice(count: 1, repeatedValue:1)
let s2 : Slice<Int> = Slice(count: 1, repeatedValue:1)

var b1 = s1[0..1] == s2  // false
var b2 = s1 == s2        // true

Чтобы узнать, что произошло, я поместил его как unit test в проект Xcode и проверил код разборки

Начните с правильного кода:

func testSlice2() {
    b2 = s1 == s2
}

Xcode дайте мне это

test2Tests`test2Tests.VariableTests.testSlice2 (test2Tests.VariableTests)() -> () at test2Tests.swift:38:
0x1000ec120:  pushq  %rbp
0x1000ec121:  movq   %rsp, %rbp
0x1000ec124:  subq   $0x80, %rsp
0x1000ec12b:  movq   %rdi, -0x8(%rbp)
0x1000ec12f:  movq   %rdi, -0x10(%rbp)
0x1000ec133:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ec138:  movq   -0x10(%rbp), %rdi
0x1000ec13c:  movq   %rax, -0x18(%rbp)
0x1000ec140:  callq  0x1000efd8c               ; symbol stub for: object_getClass
0x1000ec145:  movq   -0x10(%rbp), %rdi
0x1000ec149:  callq  *0x50(%rax)
0x1000ec14c:  movq   -0x10(%rbp), %rdi
0x1000ec150:  movq   %rax, -0x20(%rbp)
0x1000ec154:  movq   %rdx, -0x28(%rbp)
0x1000ec158:  movq   %rcx, -0x30(%rbp)
0x1000ec15c:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ec161:  movq   -0x10(%rbp), %rcx
0x1000ec165:  movq   %rcx, %rdi
0x1000ec168:  movq   %rax, -0x38(%rbp)
0x1000ec16c:  callq  0x1000efd8c               ; symbol stub for: object_getClass
0x1000ec171:  movq   0x4ed8(%rip), %rcx        ; (void *)0x00000001047bd8b0: direct type metadata for Swift.Int
0x1000ec178:  addq   $0x8, %rcx
0x1000ec17f:  movq   0x4ef2(%rip), %rdx        ; (void *)0x00000001047b6fc8: protocol witness table for Swift.Int : Swift.Equatable
0x1000ec186:  movq   -0x10(%rbp), %rdi
0x1000ec18a:  movq   %rdx, -0x40(%rbp)
0x1000ec18e:  movq   %rcx, -0x48(%rbp)
0x1000ec192:  callq  *0x58(%rax)
0x1000ec195:  movq   -0x20(%rbp), %rdi
0x1000ec199:  movq   -0x28(%rbp), %rsi
0x1000ec19d:  movq   -0x30(%rbp), %r8
0x1000ec1a1:  movq   %rdx, -0x50(%rbp)
0x1000ec1a5:  movq   %r8, %rdx
0x1000ec1a8:  movq   %rcx, -0x58(%rbp)
0x1000ec1ac:  movq   %rax, %rcx
0x1000ec1af:  movq   -0x50(%rbp), %r8
0x1000ec1b3:  movq   -0x58(%rbp), %r9
0x1000ec1b7:  movq   -0x48(%rbp), %rax
0x1000ec1bb:  movq   %rax, (%rsp)
0x1000ec1bf:  movq   -0x40(%rbp), %r10
0x1000ec1c3:  movq   %r10, 0x8(%rsp)
0x1000ec1c8:  callq  0x1000efc3c               ; symbol stub for: Swift.== @infix <A : Swift.Equatable>(Swift.Slice<A>, Swift.Slice<A>) -> Swift.Bool
0x1000ec1cd:  movq   -0x10(%rbp), %rdi
0x1000ec1d1:  movb   %al, -0x59(%rbp)
0x1000ec1d4:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ec1d9:  movb   -0x59(%rbp), %r11b
0x1000ec1dd:  movzbl %r11b, %edi
0x1000ec1e1:  movq   %rax, -0x68(%rbp)
0x1000ec1e5:  callq  0x1000efdb0               ; symbol stub for: ObjectiveC._convertBoolToObjCBool (Swift.Bool) -> ObjectiveC.ObjCBool
0x1000ec1ea:  movq   0x552f(%rip), %rsi        ; "setB2:"
0x1000ec1f1:  movq   -0x10(%rbp), %rcx
0x1000ec1f5:  movq   %rcx, %rdi
0x1000ec1f8:  movzbl %al, %edx
0x1000ec1fb:  callq  0x1000efd6e               ; symbol stub for: objc_msgSend
0x1000ec200:  movq   -0x10(%rbp), %rdi
0x1000ec204:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec209:  movq   -0x10(%rbp), %rdi
0x1000ec20d:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec212:  addq   $0x80, %rsp
0x1000ec219:  popq   %rbp
0x1000ec21a:  retq   

Нетрудно определить эту строку

0x1000ec1c8:  callq  0x1000efc3c               ; symbol stub for: Swift.== @infix <A : Swift.Equatable>(Swift.Slice<A>, Swift.Slice<A>) -> Swift.Bool

перегружен оператор == вызывается для сравнения значения


Теперь для кода с ошибкой

func testSlice1() {
    b1 = s1[0..1] == s2
}

Xcode дайте мне это

test2Tests`test2Tests.VariableTests.testSlice1 (test2Tests.VariableTests)() -> () at test2Tests.swift:34:
0x1000ebec0:  pushq  %rbp
0x1000ebec1:  movq   %rsp, %rbp
0x1000ebec4:  pushq  %r14
0x1000ebec6:  pushq  %rbx
0x1000ebec7:  subq   $0xf0, %rsp
0x1000ebece:  movq   %rdi, -0x18(%rbp)
0x1000ebed2:  movq   %rdi, -0x40(%rbp)
0x1000ebed6:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ebedb:  movq   -0x40(%rbp), %rdi
0x1000ebedf:  movq   %rax, -0x48(%rbp)
0x1000ebee3:  callq  0x1000efd8c               ; symbol stub for: object_getClass
0x1000ebee8:  movq   0x5161(%rip), %rdi        ; (void *)0x00000001006cb8b0: direct type metadata for Swift.Int
0x1000ebeef:  addq   $0x8, %rdi
0x1000ebef6:  movq   0x5163(%rip), %r8         ; (void *)0x00000001006c5158: protocol witness table for Swift.Int : Swift.ForwardIndex
0x1000ebefd:  movq   0x5164(%rip), %rcx        ; (void *)0x00000001006c5120: protocol witness table for Swift.Int : Swift._SignedInteger
0x1000ebf04:  movq   0x5165(%rip), %rdx        ; (void *)0x00000001006c4f90: protocol witness table for Swift.Int : Swift._BuiltinIntegerLiteralConvertible
0x1000ebf0b:  leaq   -0x38(%rbp), %rsi
0x1000ebf0f:  leaq   -0x28(%rbp), %r9
0x1000ebf13:  leaq   -0x20(%rbp), %r10
0x1000ebf17:  movq   -0x40(%rbp), %r11
0x1000ebf1b:  movq   %rdi, -0x50(%rbp)
0x1000ebf1f:  movq   %r11, %rdi
0x1000ebf22:  movq   %r10, -0x58(%rbp)
0x1000ebf26:  movq   %r8, -0x60(%rbp)
0x1000ebf2a:  movq   %rcx, -0x68(%rbp)
0x1000ebf2e:  movq   %rdx, -0x70(%rbp)
0x1000ebf32:  movq   %rsi, -0x78(%rbp)
0x1000ebf36:  movq   %r9, -0x80(%rbp)
0x1000ebf3a:  callq  *0x50(%rax)
0x1000ebf3d:  movq   $0x0, -0x20(%rbp)
0x1000ebf45:  movq   $0x1, -0x28(%rbp)
0x1000ebf4d:  movq   -0x58(%rbp), %rsi
0x1000ebf51:  movq   -0x80(%rbp), %rdi
0x1000ebf55:  movq   -0x78(%rbp), %r8
0x1000ebf59:  movq   %rdi, -0x88(%rbp)
0x1000ebf60:  movq   %r8, %rdi
0x1000ebf63:  movq   -0x88(%rbp), %r8
0x1000ebf6a:  movq   %rdx, -0x90(%rbp)
0x1000ebf71:  movq   %r8, %rdx
0x1000ebf74:  movq   -0x50(%rbp), %r9
0x1000ebf78:  movq   %rcx, -0x98(%rbp)
0x1000ebf7f:  movq   %r9, %rcx
0x1000ebf82:  movq   -0x60(%rbp), %r8
0x1000ebf86:  movq   -0x68(%rbp), %r10
0x1000ebf8a:  movq   %r10, (%rsp)
0x1000ebf8e:  movq   -0x50(%rbp), %r11
0x1000ebf92:  movq   %r11, 0x8(%rsp)
0x1000ebf97:  movq   %r11, 0x10(%rsp)
0x1000ebf9c:  movq   -0x70(%rbp), %rbx
0x1000ebfa0:  movq   %rbx, 0x18(%rsp)
0x1000ebfa5:  movq   %rax, -0xa0(%rbp)
0x1000ebfac:  callq  0x1000ecac0               ; Swift... @infix <A : Swift.ForwardIndex>(A, A) -> Swift.Range<A>
0x1000ebfb1:  movq   0x5098(%rip), %rax        ; (void *)0x00000001006cb8b0: direct type metadata for Swift.Int
0x1000ebfb8:  addq   $0x8, %rax
0x1000ebfbe:  movq   -0x38(%rbp), %rdi
0x1000ebfc2:  movq   -0x30(%rbp), %rsi
0x1000ebfc6:  movq   -0xa0(%rbp), %rdx
0x1000ebfcd:  movq   -0x90(%rbp), %rcx
0x1000ebfd4:  movq   -0x98(%rbp), %r8
0x1000ebfdb:  movq   %rax, %r9
0x1000ebfde:  callq  0x1000efc72               ; symbol stub for: Swift.Slice.subscript.getter (Swift.Range<Swift.Int>) -> Swift.Slice<A>
0x1000ebfe3:  movq   0x5066(%rip), %rsi        ; (void *)0x00000001006cb8b0: direct type metadata for Swift.Int
0x1000ebfea:  addq   $0x8, %rsi
0x1000ebff1:  movq   %rax, %rdi
0x1000ebff4:  movq   %rsi, -0xa8(%rbp)
0x1000ebffb:  movq   %rdx, %rsi
0x1000ebffe:  movq   %rcx, %rdx
0x1000ec001:  movq   -0xa8(%rbp), %rcx
0x1000ec008:  callq  0x1000ec910               ; Swift.Slice.__conversion <A>(Swift.Slice<A>)() -> Swift.CConstVoidPointer
0x1000ec00d:  movq   -0x40(%rbp), %rdi
0x1000ec011:  movq   %rax, -0xb0(%rbp)
0x1000ec018:  movq   %rdx, -0xb8(%rbp)
0x1000ec01f:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ec024:  movq   -0x40(%rbp), %rcx
0x1000ec028:  movq   %rcx, %rdi
0x1000ec02b:  movq   %rax, -0xc0(%rbp)
0x1000ec032:  callq  0x1000efd8c               ; symbol stub for: object_getClass
0x1000ec037:  movq   0x5012(%rip), %rcx        ; (void *)0x00000001006cb8b0: direct type metadata for Swift.Int
0x1000ec03e:  addq   $0x8, %rcx
0x1000ec045:  movq   -0x40(%rbp), %rdi
0x1000ec049:  movq   %rcx, -0xc8(%rbp)
0x1000ec050:  callq  *0x58(%rax)
0x1000ec053:  movq   %rax, %rdi
0x1000ec056:  movq   %rdx, %rsi
0x1000ec059:  movq   %rcx, %rdx
0x1000ec05c:  movq   -0xc8(%rbp), %rcx
0x1000ec063:  callq  0x1000ec910               ; Swift.Slice.__conversion <A>(Swift.Slice<A>)() -> Swift.CConstVoidPointer
0x1000ec068:  movq   -0xb8(%rbp), %rcx
0x1000ec06f:  cmpq   %rdx, %rcx
0x1000ec072:  sete   %r14b
0x1000ec076:  movq   %rax, %rdi
0x1000ec079:  movb   %r14b, -0xc9(%rbp)
0x1000ec080:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec085:  movq   -0xb0(%rbp), %rdi
0x1000ec08c:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec091:  movq   -0x40(%rbp), %rdi
0x1000ec095:  callq  0x1000efd86               ; symbol stub for: objc_retain
0x1000ec09a:  movb   -0xc9(%rbp), %r14b
0x1000ec0a1:  movzbl %r14b, %edi
0x1000ec0a5:  movq   %rax, -0xd8(%rbp)
0x1000ec0ac:  callq  0x1000efdb0               ; symbol stub for: ObjectiveC._convertBoolToObjCBool (Swift.Bool) -> ObjectiveC.ObjCBool
0x1000ec0b1:  movq   0x5660(%rip), %rsi        ; "setB1:"
0x1000ec0b8:  movq   -0x40(%rbp), %rcx
0x1000ec0bc:  movq   %rcx, %rdi
0x1000ec0bf:  movzbl %al, %edx
0x1000ec0c2:  callq  0x1000efd6e               ; symbol stub for: objc_msgSend
0x1000ec0c7:  movq   -0x40(%rbp), %rdi
0x1000ec0cb:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec0d0:  movq   -0x40(%rbp), %rdi
0x1000ec0d4:  callq  0x1000efd80               ; symbol stub for: objc_release
0x1000ec0d9:  addq   $0xf0, %rsp
0x1000ec0e0:  popq   %rbx
0x1000ec0e1:  popq   %r14
0x1000ec0e3:  popq   %rbp
0x1000ec0e4:  retq   

Я не разбираюсь в ассемблере, но быстро просматриваю сгенерированный комментарий, я не вижу == где угодно.

Также вы можете использовать их в сборке

0x1000ec008:  callq  0x1000ec910               ; Swift.Slice.__conversion <A>(Swift.Slice<A>)() -> Swift.CConstVoidPointer

0x1000ec063:  callq  0x1000ec910               ; Swift.Slice.__conversion <A>(Swift.Slice<A>)() -> Swift.CConstVoidPointer

поэтому я думаю, что он сравнивает значение основного указателя вместо фактического содержимого срезов