Czym jest Closure w Swift?
Closure w Swift to funkcja, która nie posiada nazwy.
let myFunction = {
print ("Hello!" )
}
myFunction()
Składnia Closure
Składnia prezentuje się następująco:
{ (parameters) -> returnType in
...
}
Tak jak w "zwykłej" funkcji, ta typu Closure może posiadać parametry i możesz określić zwracany typ danych.
let calculate = { (a: Int , b: Int ) -> Int in
return a + b
}
print (calculate(4 , 3 ))
Zauważ, że w momencie wywołania funkcji typu Closure nie musimy podawać nazw parametrów, tak ja w "zwykłej" funkcji:
func substract (a: Int, b: Int) -> Int {
return a - b
}
let add = { (a: Int , b: Int ) -> Int in
return a + b
}
print (add(4 , 3 ))
print (substract(a: 10 , b: 3 ))
print (substract(10 , 3 ))
Closure jako parametr funkcji
Możesz przekazać do funkcji inną funkcję, która jest typu Closure :
let substract = { (a: Int , b: Int ) -> Int in
return a - b
}
let add = { (a: Int , b: Int ) -> Int in
return a + b
}
func calculate (a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int )) -> Int {
return operate(a, b);
}
print (calculate(a: 5 , b: 5 , operate: add))
print (calculate(a: 5 , b: 5 , operate: substract))
Trailing Closure
Jeśli funkcja przyjmuje kilka parametrów i ostatnim z nich jest Closure można wywołać ją w inny sposób.
"Standardowa" wersja:
func calculate (a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int )) -> Int {
return operate(a, b);
}
let result = calculate(a: 5 , b: 5 , operate: { (a: Int , b: Int ) -> Int in
return a + b
})
print (result)
Można wywołać to też tak:
let result = calculate(a: 5 , b: 5 ) { (a, b) in
return a + b
}
print (result)
Takie wywołanie nazwy się trailing closure .
Uproszczona składnia
Poniżej znajdziesz kilka sposobów wywołania Closure .
func calculate (a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int )) -> Int {
return operate(a, b);
}
Przykłady wywołania Closure :
calculate(a: 5 , b: 5 , operate: { (a: Int , b: Int ) -> Int in
return a + b
})
Można krócej:
calculate(a: 5 , b: 5 ) { (a, b) in
return a + b
}
Inna wersja:
calculate(a: 5 , b: 5 ) {
a, b in a + b
}
Jeszcze prostsza wersja:
calculate(a: 5 , b: 5 ) {
$0 + $1
}
$0 i $1 to referencje do parametrów Closure .
Uwaga! Można jeszcze to zapisać jeszcze inaczej:
calculate(a: 5 , b: 5 , operate: +)
Testowanie wprowadzenia danych
Kiedy potrzebujesz stestować komponent, w którym zachodzą interakcje z użytkownikiem, warto napisać test, który zasymuluje cały proces, tak jakby robił to użytkownik. Możesz to zrobić za pomocą biblioteki user-event
Przykład
Komponent:
export function MyComponent ( ) {
const [name, setName] = useState('' );
const onInputChange = e => {
setName(e.target.value);
}
return (
<>
{ name &&
<div>
Hello {name}! How are you?
</div>
}
<div>
<label htmlFor="name">Your name:</ label>
<input value={name} id="name" name="name" onChange={onInputChange} />
</div>
</ >
)
}
Kiedy użytkownik wpisze jakieś dane w pole tekstowe, na ekranie wyświetlony zostanie tekst.
Jak to przetestować?
import {render, screen} from '@testing-library/react' ;
import userEvent from '@testing-library/user-event' ;
const { getByLabelText, getByText } = screen;
test('should display greeting' , async () => {
render(<MyComponent />);
const inputName = getByLabelText('Your name:' );
await userEvent.type(inputName, 'Kacper' );
expect(getByText('Hello Kacper! How are you?' )).toBeInTheDocument();
});
Za pomocą getByLabelText i getByText pobieramy referencje do pola tekstowego i miejsca, gdzie tekst ma się wyświetlić po wpisaniu danych.
Za pomocą type z biblioteki user-event wprowadzany jest tekst do pola tekstowego. Pierwszy argument to referencja do kontrolki, dla której wpisujemy dane. Drugi argument to tekst, który chcemy przekazać.
W sierpniu opublikowałem 6 wpisów :
React
React Testing Library: Jak pobrać referencję do elementu w komponencie?
React Testing Library: Jak zasymulować kliknięcie w element?
Swift
Optional
Funkcje
Range
MongoDB
Jak sprawdzić status?
Przeczytałem dwie książki:
Ikigai - Francesc Miralles Contijoch, Hector Garcia Piugcerver
The Art and Business of Online Writing - Nicolas Cole
Przesłuchałem cztery audiobooki:
Studnia wstąpienia - Brandon Sanderson
Oko Jelenia. Drewniana twierdza - Andrzej Pilipiuk
Mindset - Dr Carol Dweck
Cyberpunk 2077: Bez przypadku - Rafał Kosik
Do czego służy Range?
Swift pozwala na tworzenie zakresu liczbowego od ...do za pomocą operatora: ... .
Przykład:
var range = 1 ...10
W tym przypadku stworzony został zakres od 1 do 10.
Zakres można wykorzystać na przykład w pętli:
for i in 1 ...10 {
print (i)
}
Swift daje do ręki programiście trzy typy zakresu:
Zamknięty
Półotwarty
Jednostronny
Zakres zamknięty
Ten typ zakresu określa jego początek i koniec . Wystarczy podać te dwie wartości:
a...b
Za pomocą first i last możesz dostać informację odpowiednio o początku i końcu zakresu:
var range = 1 ...10
print (range.first!)
print (range.last!)
Dzięki zakresowi możesz pobrać część danych ze zbioru danych:
let users = ["Greg" , "Jane" , "Spox" , "Blue" ]
let range = 0 ...2
print (users[range])
Zakres półotwarty
Zakres półotwarty określa zakres, który zawiera dane od a do b , ale bez b .
Składnia:
a..<b
Przykład:
var range = 1 ..<10
print (range.first!)
print (range.last!)
Zakres jednostronny
Jednostronny zakres definiuje wartość tylko z jednej strony zakresu:
a...
lub ...b
Jeśli zdefiniujesz zakres tak:
let range = 10 ...
To zaczyna się od 10 i kończy na... plus nieskończoności (+∞)
Z kolei:
let range = ...10
Zaczyna się na minus nieskończoności (-∞) do 10.
Gdzie można taki zakres wykorzystać?
Na przykład w tablicach.
Załóżmy, że potrzebujesz pobrać wszystkie elementy tablicy, zaczynając od drugiego elementu:
let users = ["Greg" , "Jane" , "Spox" , "Blue" ]
print (users[1 ...])
Albo, tylko pierwsze dwa elementy tablicy:
let users = ["Greg" , "Jane" , "Spox" , "Blue" ]
print (users[...1 ])
Funkcje w Swift
Składania funkcji w Swift wygląda następująco:
func name () {
...
}
Najpierw słowo kluczowe func , a następnie podajesz jej nazwę.
Wywołanie funkcji:
func helloWorld () {
print ("Hello World!)
}
helloWorld() // Hello World!
Parametry
Parametry funkcji są stałymi . To znaczy, że jeśli spróbujesz zmienić ich wartość, zostanie zgłoszony błąd.
Możesz zdefiniować parametry funkcji na różne sposoby:
Parametry z etykietą
func sayHello (name) {
print ("Hello \(name)!" )
}
Jeśli tak deklarujesz parametry funkcji, musisz podać nazwę etykiety argumentu przy wywołaniu:
sayHello(name: "Anna" )
Nie możesz napisać tak:
sayHello("Anna" )
Parametry i typ danych
Możesz określić typ danych parametrów:
func calculate (a: Int, b: Int) {
print (a + b)
}
Parametry bez etykiet
Jeśli nie chcesz używać etykiet dla argumentów, to przed nazwą parametru użyj _ :
func sayHello (_ name: String) {
print ("Hello \(name)!" )
}
sayHello("Anna" )
Domyślne wartości parametrów
Do funkcji można przekazywać domyślne wartości:
func calculate (a: Int = 1 , b: Int = 2 ) {
print (a + b)
}
Wywołanie:
calculate()
calculate(a: 9 , b: 3 )
calculate(a: 8 )
Parametry typu in-out
Jak już wyżej wspomniałem: nie można zmieniać wartości parametrów w ciele funkcji. Jeśli spróbujesz to zrobić, zostanie zgłoszony błąd.
Jeśli jednak koniecznie potrzebujesz zmienić wartość parametru, oznacz go jako: inout . Dodatkowo w momencie wywołania funkcji przed nazwą argumentu należy użyć: & .
Przykład:
func increment (_ counter: inout Int) {
counter += 1
}
var counter = 0
print (counter)
increment(&counter)
print (counter)
Parametr funkcja
Możesz do funkcji przekazać inną funkcję
func sum (_ a: Int, _ b: Int) {
print (a + b)
}
func substract (_ a: Int, _ b: Int) {
print (a - b)
}
func calculate (_ operation: (Int, Int) -> Void , _ a: Int , _ b: Int ) {
operation(a, b)
}
calculate(sum, 1 , 1 )
calculate(substract, 1 , 1 )
Zwracanie danych
Możesz określić typ danych, jaki zwraca funkcja za pomocą: return . Dzięki -> określasz typ zwracanych danych.
Zwracania jednej wartości
func calculate (a: Int, b: Int) -> Int {
return a + b
}
let result: Int = calculate(a: 5 , b: 7 )
print (result)
Zwracanie wielu wartości
Swift pozwala na zwrócenie wielu wartości . Taka funkcja zwróci krotkę (ang.: Tuple ).
func prepare (_ name: String) -> (greet: String , goodbye: String ) {
let greet: String = "Hello \(name)!"
let goodbye: String = "Bye \(name)!"
return (greet, goodbye)
}
let result = prepare("Marcin" )
print (result.greet)
print (result.goodbye)
Zwracanie funkcji
Możesz zwrócić funkcję jako wynik działania innej funkcji.
func sum (_ a: Int, _ b: Int) -> Int {
return a + b
}
func substract (_ a: Int, _ b: Int) -> Int {
return a - b
}
func defaultOperate (_ a: Int, _ b: Int) -> Int {
return 0
}
func prepare (_ op: String) -> (Int , Int ) -> Int {
if op == "+" {
return sum
} else if op == "-" {
return substract
}
return defaultOperate
}
let sumOperate = prepare("+" )
print (sumOperate(0 , 1 ))
let substractOperate = prepare("-" )
print (substractOperate(0 , 1 ))
Zagnieżdżone funkcje
Swift pozwala także na zagnieżdżone funkcje:
func calculate (_ a: Int, _ b: Int, _ op: String) -> Int {
func sum (_ a: Int, _ b: Int) -> Int {
return a + b
}
func substract (_ a: Int, _ b: Int) -> Int {
return a - b
}
if op == "+" {
return sum(a, b)
} else if op == "-" {
return substract(a, b)
}
return 0
}
print (calculate(0 , 1 , "+" ))
print (calculate(0 , 1 , "-" ))
Nowsze wpisy
Poprzednie wpisy