Как работает сравнение кортежей под капотом? - PullRequest
0 голосов
/ 25 февраля 2019
let p1 = (name: "John", age:12)
let p2 = (color: "Red", size:12)


if p1 == p2 {
    print("equal")
}else {
    print("not equal")
}

Я ожидал, что эти два кортежа будут несовместимы из-за разных имен параметров и кода, который не будет компилироваться.Но это работает отлично.Любопытно узнать как.

Свифт автоматически создает == операторов на основе типов свойств, а затем просто выполняет lhs против rhs.Это так?

РЕДАКТИРОВАТЬ:

func givePerson() -> (name: String, age: Int)? {
    return ("alex", 2)
}

func extract() {
    var p3 : (Name: String, age: Int)

    if let person = giveName() as? (Name: String, age: Int) {
        p3 = person
        print(p3)
    }else {
        print("p3 not defined")
    }

}

extract() // p3 not defined

Моя extract функция не работает, просто потому, что я неверно назвал имя arity.Это тоже ожидается?Чем это отличается от сравнения кортежей?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Стандартная библиотека определяет операторы сравнения кортежей для кортежей из 2 элементов, включая кортежи из 6 элементов.Это достигается с помощью инструмента метапрограммирования GYB (Generate Your Boilerplate), который позволяет встроенному коду Python генерировать файл из шаблона.

В результате операторы сравнения кортежей выглядят так:

public func == <A, B>(lhs: (A, B), rhs: (A, B)) -> Bool

public func == <A, B, C>(lhs: (A, B, C), rhs: (A, B, C)) -> Bool

public func == <A, B, C, D>(lhs: (A, B, C, D), rhs: (A, B, C, D)) -> Bool

// ...

Итак, с вашим кодом:

let p1 = (name: "John", age: 12)
let p2 = (color: "Red", size: 12)

if p1 == p2 {
    print("equal")
} else {
    print("not equal")
} 

Компилятор вызовет оператор сравнения двухэлементных кортежей.Вы заметите, что ни один из определенных операторов сравнения кортежей не использует метки кортежей для своих параметров.Причина, по которой
(name: String, age: Int) и (color: String, size: Int) могут быть переданы в (A, B), заключается в том, что компилятор реализует неявное преобразование, которое может лишить кортеж его меток.Таким образом, оба аргумента убирают свои метки и передаются как (String, Int).

Вот что делает следующее законное:

let p1 = (name: "John", age: 12)
let p2: (String, Int) = p1 // Legal.

Все становится страннее из-за того, что компилятор также имеетнеявное преобразование, которое может добавить произвольных меток к кортежу:

let p1 = ("John", 12)
let p2: (foo: String, bar: Int) = p1 // Legal.

Однако прямое переименование меток запрещено:

// Indirect renaming ✅
let p1 = (name: "John", age: 12)
let p2: (String, Int) = p1
let p3: (foo: String, bar: Int) = p2

// Put together ✅
let p4: (foo: String, bar: Int) = p1 as (String, Int)

// Direct renaming ❌
let p4 = (name: "John", age: 12)
let p5: (foo: String, bar: Int) = p4

И это поведение, которое вы 'увидеть с вашим as? актерский состав.Как и в приведенном выше примере, первое приведение к немаркированной форме работает:

func givePerson() -> (name: String, age: Int)? {
  return ("alex", 2)
}

func extract() {
  var p3: (Name: String, age: Int)
  if let person = givePerson() as (String, Int)? as? (Name: String, age: Int) {
    p3 = person
    print(p3)
  } else {
    print("p3 not defined")
  }

}

extract() // (Name: "alex", age: 2)
0 голосов
/ 25 февраля 2019

В кортежах определены операторы == (для кортежей от 2 до 7), но поскольку кортежи не могут соответствовать протоколам, они не Equatable.

Стандартная библиотека просто определяет 6отдельные == операторы, каждый из которых принимает два кортежа арности 2, 3, ..., 7.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...