Я запутался в значении типа () в Swift. Что это, и как я должен это использовать? - PullRequest
0 голосов
/ 23 февраля 2020

Я пытаюсь перевести высоту в футах с десятичной точки в высоту в футах и ​​дюймах.

Я пытаюсь использовать метод .round (.down), чтобы получить ноги, и умножить десятичное число на 12 для дюймов. Я получаю все виды ошибок, например, так:

var heightInFeet: Float = 5.45
let feetRounded = heightInFeet.round(.down) // feetRounded is "type ()." What is that?
percentToNextFoot = heightInFeet - feetRounded // Error: Binary operator '-' cannot be  applied to operands of type 'Float' and '()'

Я попробовал следующее и получил еще одну ошибку:

percentToNextFoot = heightInFeet - Float(feetRounded) // Cannot invoke initializer for type 'Float' with an argument list of type '(())'

Я наконец-то заработал, избегая .round ( ), но я все еще очень озадачен значением type (). Кто-нибудь может объяснить, что здесь происходит ?:

var heightInFeet: Float = 5.45
var feet = Int(heightInFeet) // 5
var percentToNextFoot = heightInFeet - Float(feet) // 0.45
let heightInFeetAndInches = "\(feet)ft \(Int(percentToNextFoot * 12))in" // 5ft 5in

Ответы [ 5 ]

3 голосов
/ 23 февраля 2020

Добро пожаловать в переполнение стека!

Double имеет два метода округления:

  1. Double.round(), которое округляет значение Double, изменяя это на месте. Это тот, кого вы назвали. Он ничего не возвращает, что, строго говоря, означает, что он возвращает Void, он же (), пустой кортеж.
  2. Double.rounded(), который округляет значение Double на возвращая новый Double. Это тот, который вы, вероятно, намеревались вызвать.

Вызывая первое и пытаясь присвоить значение переменной, вы получаете переменную типа Void, значение которой равно ().

Это распространенное соглашение Swift: "object.foo" редактирует его на месте. «object.fooed» возвращает измененную копию.

Тем не менее, в вашем случае, я бы порекомендовал сделать это с использованием существующего Measurement API:


import Foundation

extension Measurement where UnitType == UnitLength {
    func toFeetAndInches() -> (feet: Measurement<UnitLength>, inches: Measurement<UnitLength>) {
        let numberOfWholeFeet = self.converted(to: .feet).value.rounded(.towardZero)

        return (
            feet: Measurement(value: numberOfWholeFeet, unit: UnitLength.feet),
            inches: Measurement(value: self.value - numberOfWholeFeet, unit: UnitLength.feet).converted(to: .inches)
        )
    }
}


let heightInFeet = Measurement(value: 5.5, unit: UnitLength.feet)
let (feet, inches) = heightInFeet.toFeetAndInches()

let mf = MeasurementFormatter()
mf.unitOptions = .providedUnit // force the use of feet/inches, rather than the unit appropriate for the user's locale.
mf.unitStyle = .medium
print(mf.string(for: feet)!, mf.string(for: inches)!) // => "5 ft. 6 in."
2 голосов
/ 23 февраля 2020

() - сокращение от void. Это означает, что «здесь значение невозможно».

В этом примере это означает, что метод .round() ничего не возвращает - это мутирующая функция, вызываемая для его получателя. Таким образом, присвоение его пустого возврата var приводит к выводу, что тип переменной var равен void. Пустые переменные могут быть полезны, иногда, редко *, но не в этом случае.

Методы для типов значений часто встречаются парами: глагол, подобный round, и пассивный глагол, например, rounded. Первый действует непосредственно и изменяет свою цель; вторая возвращает измененную версию своей цели. Для другого примера см. sort() и sorted() для коллекций или append(_) и appending(_) для строк и т. Д. c. (* примечание: filter - раздражающее исключение; оно означает «отфильтрованный», а удобный «фильтр на месте» отсутствует).

Чтобы получить эффект, который вы добились в первом примере, rounded() - это то, что вы хотите.

-

(* Чтобы ответить на тангенциальный вопрос в вашем заголовке: как на самом деле использовать переменную void? Ну, вот как я иногда их использую :

В объекте с некоторой настройкой, который я хотел бы получить через некоторое время после init, но гарантированно не чаще одного раза в каждом экземпляре, я использовал Objective- C 's dispatch_once. Это не так доступна в Swift, так что теперь я сделаю ленивый элемент void следующим образом:

class Foo {
  lazy var setup: () = {
    // do some complicated stuff I couldn't do in `init` for some reason
    // this will only run once
  }()

  func doSomethingUseful() {
    _ = setup // runs the setup initializer just the first time we get here
    // do useful things that depend on setup having happened
  }
}

Я оставлю это на усмотрение комментариев, чтобы судить, действительно ли мы «собирались» использовать такую ​​технику.: )

2 голосов
/ 23 февраля 2020

Если вы посмотрите на ссылку для функции округления типа Float, вы увидите, что она ничего не возвращает. Он просто изменяет число с плавающей точкой, на которой вы вызвали этот метод.

Вы можете сделать

var feetRounded = heightInFeet                  
feetRounded.round(.down)
1 голос
/ 23 февраля 2020

round меняет значение на месте ; Вы используете это так:

var heightInFeet: Float = 5.45
heightInFeet.round(.down)

Вы заметили, что значение не возвращается; во второй строке нет =. Нам не нужно ничего устанавливать в результат вызова round, потому что он не имеет результата.

Если, как и в вашем коде, вы случайно do захватить «результат», он выражается как тип (). Таким образом, () является типом результата вызова метода, который не имеет результата.

Когда мы случайно напишем это:

var heightInFeet: Float = 5.45
let x = heightInFeet.round(.down)

, мы получим эту ошибку : «Константа 'x' подразумевает тип '()', что может быть неожиданным." Это просто причудливый способ сказать: «Вы взяли вызов метода, который не дал результата, и захватили его« результат ». Вы, вероятно, не хотели этого делать!» И действительно, вы этого не сделали.

1 голос
/ 23 февраля 2020

Пожалуйста, ознакомьтесь с документацией . Метод

mutating func round(_ rule: FloatingPointRoundingRule)

не имеет возвращаемого значения (он же Void он же ())

Если вам нужен результат, вы должны использовать округлено (_:) который имеет возвращаемое значение

func rounded(_ rule: FloatingPointRoundingRule) -> Float
...