Hi, Habr! On June 2, we all could witness how Apple began to revolutionize the Objective-C camp of developers by introducing its new programming language, Swift, to the world. At the same time, she posted in open access a small documentation on the language, which we decided to translate, if there is demand. We offer you the translation of the first chapter. If the topic is interesting, we will continue to publish the translation every week. “Hello, world” . With Swift, this is done like this: println("Hello, world") main function is no longer needed. Also note the absence of a semicolon at the end of each line.Comment
For a better understanding of the material, we recommend using the playground mode in Xcode. Playground allows you to see the result immediately in the code editing process without having to compile and run the application.
let to create a constant and var to create a variable. You don't need to specify a constant type; you can assign a value to it only once. var myVariable = 42 myVariable = 50 let myConstant = 42 myVariable is of integer type. let implicitInteger = 70 let inplicitDouble = 70.0 let inplicitDouble: Double = 70 Let's experiment
Create a constant with type Float and initialize it with the number 4.
let label = "The width is " let width = 94 let widthLabel = label + String(width) Let's experiment
Try removing the explicit conversion to the String type in the last line. What error do you get?
\ ) in front of them. Example: let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit." Let's experiment
Try using the\()construct and display a string that includes the result of the sum of two integer variables and someone's name.
[] ) are used: var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations" let emptyArray = String[]() let emptyDictionary = Dictionary<String, Float>() [] and [:] respectively, for example, when you assign a new value to a variable or pass an argument to a function. shoppingList = [] // Went shopping and bought everything. if and switch , to create loops - for-in , for , while and do-while . In this case, it is not necessary to select conditions and initializing expressions in parentheses, while curly brackets are required. let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } teamScore if should be logical, which in particular means that the expression if score {…} is erroneous, since there is no explicit comparison (for example, with zero).if can be used in conjunction with let and var to work with constants and variables that can be nil . Such constants and variables are called optional (that is, they can either take a value or be equal to nil ). To create an optional variable or constant add a question mark ( ? ) After specifying the type. var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" } Let's experiment
ChangeoptionalNametonil. What do you see on the screen? Add anelseblock to handle the case whenoptionalNameisnil.
nil , the condition will be false and the code in braces after the if will not be executed. Otherwise, the variable greeting will be assigned a new value.switch multiple select switch supports many other comparison operators within it and is not limited to simple comparisons: let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": let vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment = "Is it a spicy \(x)?" default: let vegetableComment = "Everything tastes good in soup." } Let's experiment
Try removing the default condition. What error do you get?
switch without checking the subsequent conditions. Thus, you do not need to manually add interrupts ( break ) at the end of each case block.for-in operator along with a pair of names for each key-value pair. let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25], ] var largest = 0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } largest Let's experiment
Add another variable that will allow you to find out which of the three types the maximum number found is.
while operator allows you to execute a block of code inside it until the condition becomes false. The condition can also be specified after the block, which in this case will be executed at least once. var n = 2 while n < 100 { n = n * 2 } n var m = 2 do { m = m * 2 } while m < 100 m .. ) or using an initializer, condition, and increment. Look, these two cycles do the same thing: var firstForLoop = 0 for i in 0..3 { firstForLoop += i } firstForLoop var secondForLoop = 0 for var i = 0; i < 3; ++i { secondForLoop += 1 } secondForLoop .. ) if you do not want to include a larger value in the range, and three points ( … ) to include both smaller and larger values.func keyword. The function is called by specifying its name and the list of arguments in parentheses. The return type should be separated from the list of formal arguments with -> . func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday") Let's experiment
Remove the day parameter. Instead, add a variable denoting the name of the dish served for lunch.
func getGasPrices() -> (Double, Double, Double) { return (3.59, 3.69, 3.79) } getGasPrices() func sumOf(numbers: Int...) -> Int { var sum = 0 for number in numbers { sum += number } return sum } sumOf() sumOf(42, 597, 12) Let's experiment
Write a function that allows you to find the arithmetic mean of an arbitrary number of its arguments.
func returnFifteen() -> Int { var y = 10 func add() { y += 5 } add() return y } returnFifteen() func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() increment(7) func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool { for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int) -> Bool { return number < 10 } var numbers = [20, 19, 7, 12] hasAnyMatches(numbers, lessThanTen) {} ). To separate the arguments and return type from the closure body, use the in operator. numbers.map({ (number: Int) -> Int in let result = 3 * number return result }) Let's experiment
Rewrite the closure so that it returns zero for all unnecessary numbers.
numbers.map({ number in 3 * number }) sort([1, 5, 3, 12, 2]) { $0 > $1 } class . Class members are declared in the same way as regular constants and variables. Moreover, class methods are declared as ordinary functions. class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } } Let's experiment
Add a class constant member and a class method that takes it as its argument.
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription() init method. class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } } self is separated from the argument of the name constructor. Arguments are passed to the constructor in the usual way, as in any other class method. Note that each member of the class must be initialized — either when declaring (as, for example, numberOfSides ), or in the constructor (as name ).deinit method, which can be rewritten if necessary.override child class must be marked with the override keyword — overriding methods without override will result in an error. The compiler also identifies methods labeled override , but not overriding any methods of their parent class. class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." } } let test = Square(sideLength: 5.2, name: "my test square") test.area() test.simpleDescription() Let's experiment
Create aCircleclass and inherit it from theNamedShapeclass. The constructor of theCircleclass takes two arguments, the radius and the name. Overrideareamethods anddescribethis class.
getter and setter . class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triagle with sides of length \(sideLength)." } } var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") triangle.perimeter triangle.perimeter = 9.9 triangle.sideLength setter perimeter variable perimeter new value assigned is implicitly called newValue . You can change the name of this variable by specifying it in brackets immediately after set .EquilateralTriangle class. This method involves three consecutive steps:willSet and didSet methods in the way you want. For example, in the class below, it is guaranteed that the length of the side of the triangle will always be equal to the length of the side of the square. class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength times ) that will be used only inside this method. In this case, to call this method, you must use the first name ( numberOfTimes ). class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7) ? ) Before methods, class members, etc. If the value before the question mark is nil , everything that follows ( ? ) ? ignored and the value of the whole expression is nil . Otherwise, the expression is evaluated in the usual way. In both cases, the result of the entire expression is an optional value. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength enum keyword is used to create enum . Note that enumerations can also include methods. enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.toRaw()) } } } let ace = Rank.Ace let aceRawValue = ace.toRaw() Let's experiment
Write a function that compares 2Ranktype listings by their values.
toRaw and fromRaw . if let convertedRank = Rank.fromRaw(3) { let threeDescription = convertedRank.simpleDescription() } enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription() Let's experiment
Add aColormethod that returns the string“black”forSpadesandClubsand“red”forHeartsandDiamonds.
Hearts member accesses the Suit enumeration. When assigning a value to the constant of hearts , the full name Suit.Hearts , since we obviously do not indicate the type of this constant. And in switch we use the abbreviated form .Hearts , since the type of self is known a priori. You can use the short form everywhere if the variable type is explicitly specified.struct keyword is used to create structures. Structures have many similar features with classes, including methods and constructors. One of the most significant differences between structures and classes is that instances of structures, unlike instances of classes, are passed to functions by value (that is, they create a local copy first), while instances of classes are passed by reference. struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription() Let's experiment
Add a method to the Card structure that creates a complete deck of cards.
success constant in the example). Associated and initial values are different things: the initial value of an enumeration member is always constant for all instances of the enumeration and is indicated when it is declared. enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): let serverResponse = "Failure... \(error)" } Let's experiment
Add a third option to theswitchmultiple selectswitch
ServerResponse object. protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() } class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class." var anotherProperty: Int = 69105 func adjust() { simpleDescription += " Now 100% adjusted." } } var a = SimpleClass() a.adjust() let aDescription = a.simpleDescription struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { simpleDescription += " (adjusted)" } } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription Let's experiment
Create an enumeration that will implement this protocol.
mutating keyword in the definition of the SimpleStructure structure, which informs the compiler that the corresponding method SimpleStructure structure change. In contrast, SimpleClass class SimpleClass do not need to be labeled as mutating , since class methods can always change it freely.extensions. You can also use extensions to implement a protocol of an already existing type, even if it is imported from any library or framework. extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } 7.simpleDescription Let's experiment
Create a type extensionDoublewith a member variableabsoluteValue.
let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the error protocolValueis of type SimpleClass, the compiler assumes that its type is ExampleProtocol. This means that you cannot accidentally gain access to methods or members of a class that are implemented outside the protocol ExampleProtocol.<>). func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] { var result = ItemType[]() for i in 0..times { result += item } return result } repeat("knock", 4) // Reimplement the Swift standard library's optional type enum OptionalValue<T> { case None case Some(T) } var possibleInteger: OptionalValue<Int> = .None possibleInteger = .Some(100) where. func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements([1, 2, 3], [3]) Let's experiment.
Modify the functionanyCommonElementsso that it returns an array of common elements.
whereand write the name of the protocol or class after the colon. An expression is <T: Equatable>equivalent to an expression <T where T: Equatable>.Source: https://habr.com/ru/post/225841/
All Articles