Урок 17. Функции Часть2

26 Февраля 2023

Задача 17.1 📚

Реализуйте функцию, которая принимает три параметра цена за единицу товара, количество товаров и скидка в процентах. Функция должна возвращать общую стоимость заказа, после применения скидки. 

Если значение параметра со скидкой не передано в функцию, то функция должна применять скидку в размере  0%

Все параметры должны иметь тип Double.

Если вы производите операции с типом Int, то будьте готовы, что результат не округляется до целого числа, компилятор просто отбросит все что будет после запятой. Например операция деления 20 на 100 будет равна 0, так как все что было после запятой компилятор отбросил.  

В дальнейшем вы узнаете как делать вычисления с разными типами данных. 

				
					func calculatePrice(unitPrice: Double, quantity: Double, discount: Double = 0.0) -> Double {
    let totalPrice = unitPrice * quantity
    let discountAmount = totalPrice * discount
    return totalPrice - discountAmount
}

// Вызов функции без параметра скидки
let price1 = calculatePrice(unitPrice: 10.0, quantity: 5)
print(price1) // Выведет "50.0"

// Вызов функции с параметром скидки
let price2 = calculatePrice(unitPrice: 10.0, quantity: 5, discount: 0.2)
print(price2) // Выведет "40.0"
				
			

Функция принимает три параметра, обратите внимание на название функции, это действие, поэтому оно должно быть глаголом. Имена параметров информативные без сокращений. 

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

Что же касается логики, то здесь все просто, сперва находим общую сумму totalPrice, путем умножения unitPrice на quantity, а затем вычисляем размер скидки discountAmount, путем умножения totalPrice на discount. В конце функция вычисляет финальную цену , вычитанием скидки из общей стоимости и возвращает ее. 

Благодаря тому что у нас есть значения по умолчанию, в решении выше, вы можете видеть два вызова функции. Первый вызов передает только два параметра, а функция использует значение по умолчанию для параметра discount. Второй вызов функции передает все три параметра, включая значение discount. 

Если вы решили без дополнительных свойств:

				
					func getTotalPrice(price: Double, quantity: Double, discount: Double = 0) -> Double {
	price * quantity - price * quantity * (discount / 100)
}

getTotalPrice(price: 10, quantity: 5, discount: 20)
				
			

То это тоже считается хорошим решением, так как расчеты не сильно объемные, и можно не создавать лишних сущностей.

Обратите внимание что параметр discount необходимо пропускать в том случае если у вас скидка равна 0:

				
					getTotalPrice(price: 10, quantity: 5)
				
			

Так же следите за синтаксисом объявленой функции, после имени и перед открывающей круглой скобкой не должно быть пробела.

Задача 17.2 📚

Для направлений лучше использовать перечисление. В качестве параметра определите вариативный параметр с типом перечисления. 

Создайте функцию, которая принимает в качестве параметров любое количество направлений (север, юг, запад и восток) и выводит на консоль сообщение о том в каком направлении находится пользователь. Ваша задача вызвать функцию с несколькими значениями направления, например если мы передадим в функцию значение север и юг, то должны увидеть на консоли сообщения:

				
					
// Вывод:
// Heading north
// Heading south
				
			
				
					enum Direction {
  case north, south, east, west
}

func printDirections(_ directions: Direction...) {
  for direction in directions {
    print("Heading \(direction)")
  }
}

printDirections(.north, .west, .south)
				
			

Функция printDirections принимает произвольное количество значений типа Direction, то есть параметр должен быть вариативный.  И выводит в консоль сообщения о направлении, соответствующие каждому переданному значению. 

Для этого внутри функции используется цикл for – in, который перебирает все переданные значения и при помощи интерполяции выводит результат на консоль. 

Обратите внимание на пропуск аргумента в параметре, название не должно дублироваться.

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

				
					func printDirections(_ directions: String...) {
  for direction in directions {
	  print("Heading \(direction)")
  }
}

printDirections("north", "west", "south")
				
			

Ваша программа будет отлично справляться с поставленной задачей, но такой код очень сложно поддерживать, и плюс ко всему вы не защищены от ошибок. Так как работаете со строками, любая опечатка может привести к не желательному результату. Вы должны стараться сделать ваш код максимально безопасным.  

Так же здесь не очень подойдет решение с использованием конструкции if-else:

				
					func printDirections(_ directions: String...) {
    for direction in directions {
        if direction == "north" {
            print("Heading north")
        } else if direction == "south" {
            print("Heading south")
        } else if direction == "east" {
            print("Heading east")
        } else {
            print("Heading west")
        }
    }
}


printDirections("north", "west", "south")
				
			

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

Ну и плюс ко всему если у вас стоит задача сопоставить значения, то здесь лучше подойдет перечисление:

				
					enum Direction {
  case north, south, east, west
}

func printDirections(_ directions: Direction...) {
  for direction in directions {
	switch direction {
	case .north:
	  print("Heading north")
	case .south:
	  print("Heading south")
	case .east:
	  print("Heading east")
	case .west:
	  print("Heading west")
	}
  }
}

printDirections(.north, .west, .south)
				
			

Конечно нужно смотреть по обстоятельствам, и иногда  if лучше подходит, даже с перечислением, например если тебе необходимо найти только одно направление:

				
					func printDirections(_ directions: Direction...) {
  for direction in directions {
      if direction == .north {
          print("Right direction")
      } else {
          print("You are moving in the wrong direction")
      }
  }
}

printDirections(.north, .west, .south)
				
			

В таком случае if будет удобней, потому как switch с одним кейсом и дефолтной веткой избыточен. 

Просто запомните, если у вас стоит задача перебрать все значения и под каждое значение определить действие, то здесь отлично подойдет switch, во всех остальных случаях можно использовать if.  Но в нашем конкретном примере ни switch ни if здесь не нужны.

Задача 17.3 📚

Для решения этой задачи вам нужно использовать внутри основной функции новое свойство, которое будет хранить результат, и цикл от 1 до параметра, который отвечает за количество итераций. 

Создайте функцию, которая будет удваивать переданное ей значение типа Int, и возвращать этот результат. 

Далее создайте еще одну функцию, которая будет принимать три параметра: функцию созданную ранее, значение, которое планируем увеличивать в два раза и число, которое будет отвечать за количество вызовов, переданной в параметр функции. 

Функция должна выводить следующий результат на консоль: “Operation result after iteration <номер итерации> is: <результат>

Например если мы захотим 5 раз увеличить число 3, то на консоли мы  должны получить следующий результат:

				
					
// Вывод:
// Operation result after iteration 1 is: 6
// Operation result after iteration 2 is: 12
// Operation result after iteration 3 is: 24
// Operation result after iteration 4 is: 48
// Operation result after iteration 5 is: 96
				
			
				
					func increaseValue(_ value: Int) -> Int {
    value * 2 // ключевое слово return здесь будет лишним
}

func repeatOperation(_ operation: (Int) -> Int, with value: Int, numberOfIterations: Int) {
    var result = value
    
    for iteration in 1...numberOfIterations {
        result = operation(result)
        print("Operation result after iteration \(iteration) is: \(result)")
    }
}

// Пример использования функции repeatOperation:
repeatOperation(increaseValue, with: 3, numberOfIterations: 5)
// Вывод:
// Operation result after iteration 1 is: 6
// Operation result after iteration 2 is: 12
// Operation result after iteration 3 is: 24
// Operation result after iteration 4 is: 48
// Operation result after iteration 5 is: 96
				
			

Функция increaseValue удваивает переданное ей значение типа Int и возвращает результат. Обратите внимание на пропущенный аргумент в параметрах. Таким образом мы избегаем дублирования слова value в названии функции. 

Функция repeatOperation принимает три параметра: функцию operation, которую нужно выполнить с начальным значением value и количеством итераций numberOfIteration. 

Внутри функции repeatOperation мы используем цикл for, что бы вызвать функцию operation нужное количество раз и выводим результат на консоль при каждой итерации. 

После чего мы вызываем функцию 5 раз с значением 3. 

Давайте подробно разберем решение этой задачи. 

Отбросим основную функцию и выполним простое решение:

				
					func increaseValue(_ value: Int) -> Int {
    value * 2
}

var result = 3

for iteration in 1...5 {
    result = increaseValue(result)
    print("Operation result after iteration \(iteration) is: \(result)")
}
				
			

У нас есть начальное значение 3. Запускаем цикл, который будет крутить 5 итераций, внутри мы каждый раз вызываем функцию increaseValue, а ее результат присваиваем свойству result, то есть каждую итерацию result будет иметь новое значение.

Если вы не понимаете как увеличивается result то советую освежить тему циклов (ссылка на цикл while, но в данном примере очень хорошо видно, как мы увеличиваем свойство count каждую итерацию)

По факту в функции repeatOperation делаем тоже самое, только значения 3, 5 и функцию для увеличения мы получаем из параметров. 

Поддержите наш проект, и помогите изменить подход к обучению!

Развивайся вместе с нами

Поддержите наш проект, и помогите изменить подход к обучению!

Address List

Social Networks

Поддержите наш проект, и помогите изменить подход к обучению!