Як швидко визначити статичну константу в класі


105

У своїй функції я маю таке визначення, яке працює

class MyClass {
    func myFunc() {
        let testStr = "test"
        let testStrLen = countElements(testStr)
    }
}

Але якщо я переміщу 'testStr' і 'testStrLen' на рівень класу, він не буде компілюватися. Він сказав, що "MyClass.Type не має члена з ім'ям" testStr ".

class MyClass {
    let testStr = "test"
    let testStrLen = countElements(testStr)

    func myFunc() {

    }
}

Як я можу це виправити? Я не хочу платити пеню за підрахунок постійного "тесту" кожного разу.

Виходячи з мого розуміння коментарів нижче, мені потрібно зробити це:

class MyClass {
    let testStr = "test"
    let testStrLen = countElements("test")

    func myFunc() {

    }
}

Чи є спосіб мені не потрібно вводити / вводити "тест" двічі? Дякую.


3
можливий дублікат ViewControl.Type не має члена з ім’ям (Початкове значення властивості не може залежати від іншого властивості.)
Martin R

1
можливий дублікат Зміна X і Y у CGRectMake (з приємним рішенням із використанням лінивого властивості)
Martin R

"Чи є спосіб мені не потрібно вводити / вводити" тест "двічі?" - Так. Перемістіть ініціалізацію testStrLen в метод init (як це запропоновано у відповіді на перший можливий дублікат) або скористайтеся ледачою ініціалізацією (як це запропоновано у відповіді на другий можливий дублікат).
Мартін Р

Відповіді:


177

Можливо, приємною ідіомою для декларування констант для класу в Swift є просто використання структури з назвою MyClassConstants, як описано нижче.

struct MyClassConstants{
    static let testStr = "test"
    static let testStrLength = countElements(testStr)

    static let arrayOfTests: [String] = ["foo", "bar", testStr]
}

Таким чином ваші константи будуть розміщені в межах заявленої конструкції, а не пливуть по всьому світу.

Оновлення

Я додав константу статичного масиву у відповідь на коментар із запитанням про ініціалізацію статичного масиву. Дивіться літературу Array у "Швидкій мові програмування".

Зауважте, що для ініціалізації масиву можуть використовуватися як рядкові літерали, так і строкова константа. Однак, оскільки тип масиву відомий, ціла константа testStrLengthне може бути використана в ініціалізаторі масиву.


2
Не могли б ви замість цього просто оголосити константи статичними приватними? Хіба вони тоді не стали б глобальними?
sethfri

3
б'є, використовуючи .rawValue, як я використовував enum
DogCoffee

1
Це не буде найкращим рішенням, якщо код використовуватиметься і від Objective C, оскільки структури Swift не переведені на Objective C
mbpro

1
Яка різниця між декларуванням staticконстант в Structі в Classес?
Jauzee

1
@YOUNG Swift 2.2 Перерахування можуть спрацювати, але, як правило, перетворюється на більш сильну семантичну асоціацію, ніж просто групування констант загалом. У посиланні Swift перерахунки містять як асоційовані, так і необроблені значення. Ви можете використовувати необроблені значення, але синтаксис - це MyClassConstants.testStr.rawValueотримати доступ до значення, яке не так синтаксично, як просто MyClassConstants.testStr.
Мартін Вулстенхульме

72

Додавання до відповіді @ Мартіна ...

Якщо хтось планує тримати постійний файл рівня програми, ви можете згрупувати константу залежно від їх типу або характеру

struct Constants {
    struct MixpanelConstants {
        static let activeScreen = "Active Screen";
    }
    struct CrashlyticsConstants {
        static let userType = "User Type";
    }
}

Виклик: Constants.MixpanelConstants.activeScreen

ОНОВЛЕННЯ 5/5/2019 (щось на кшталт теми, але 🤷🏽‍♂️)

Прочитавши деякі рекомендації щодо коду та з особистого досвіду, здається, що структури не є найкращим підходом для зберігання глобальних констант з кількох причин. Особливо наведений вище код не перешкоджає ініціалізації структури. Ми можемо досягти цього, додавши код котла, але є кращий підхід

ENUMS

Те саме можна досягти, використовуючи enum із більш безпечним та чітким поданням

enum Constants {
    enum MixpanelConstants: String {
        case activeScreen = "Active Screen";
    }
    enum CrashlyticsConstants: String {
        case userType = "User Type";
    }
}

print(Constants.MixpanelConstants.activeScreen.rawValue)

2
Дякую. Мені це подобається, забезпечує елегантний спосіб управління константами через struct.
Abhijeet

1
З великою кількістю прикладів , які я додав кращий підхід тут
Аніш Parajuli 웃

15

Якщо я правильно розумію ваше запитання, ви запитуєте, як можна створити константи рівня класу (статичні - на мові C ++), щоб ви не: а) повторювали накладні витрати в кожному випадку, і b повинні перерахувати те, що інакше є постійним.

Мова еволюціонувала - як знає кожен читач, але, як я тестую це в Xcode 6.3.1, рішення:

import Swift

class MyClass {
    static let testStr = "test"
    static let testStrLen = count(testStr)

    init() {
        println("There are \(MyClass.testStrLen) characters in \(MyClass.testStr)")
    }
}

let a = MyClass()

// -> There are 4 characters in test

Я не знаю, чи потрібна статика, оскільки компілятор, безумовно, додає лише один запис змінної const у статичний розділ бінарного файлу, але це впливає на синтаксис та доступ. Використовуючи статичні, ви можете звернутися до нього , навіть якщо у вас немає примірника: MyClass.testStrLen.


11

Якщо ви дійсно хочете статичну властивість свого класу, це не підтримується в Swift. Поточна порада - це подолати, використовуючи глобальні константи:

let testStr = "test"
let testStrLen = countElements(testStr)

class MyClass {
    func myFunc() {
    }
}

Якщо ви хочете, щоб вони були властивостями екземпляра, ви можете використовувати властивість, що зберігається ліниво, на довжину - вона буде оцінена лише при першому зверненні, тому ви не будете обчислювати її знову і знову.

class MyClass {
    let testStr: String = "test"
    lazy var testStrLen: Int = countElements(self.testStr)

    func myFunc() {
    }
}

1
+1 Шкода, що все ще здається не кращим способом, ніж ці глобальні змінні.
Друкс

1
Я знаю, що це мовне обмеження на даний момент, але я б скоріше уникав використання глобальних за будь-яку ціну. Я думаю, що використання кращих контейнерів без щось подібне ClassNameConstants було б кращим підходом.
Зорайр

7

Що з використанням обчислених властивостей?

class MyClass {
  class var myConstant: String { return "What is Love? Baby don't hurt me" }
}

MyClass.myConstant

7

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

приватне ключове слово можна використовувати для обмеження обсягу констант у тому ж самому швидкому файлі.

class MyClass {

struct Constants {

    static let testStr = "test"
    static let testStrLen = testStr.characters.count

    //testInt will not be accessable by other classes in different swift files
    private static let testInt = 1
}

func ownFunction()
{

    var newInt = Constants.testInt + 1

    print("Print testStr=\(Constants.testStr)")
}

}

Інші класи зможуть отримати доступ до констант класу, як показано нижче

class MyClass2
{

func accessOtherConstants()
{
    print("MyClass's testStr=\(MyClass.Constants.testStr)")
}

} 

2

Спробував на дитячому майданчику


class MyClass {

struct Constants { static let testStr = "test" static let testStrLen = testStr.characters.count //testInt will not be accessable by other classes in different swift files private static let testInt = 1 static func singletonFunction() { //accessable print("Print singletonFunction testInt=\(testInt)") var newInt = testStrLen newInt = newInt + 1 print("Print singletonFunction testStr=\(testStr)") } } func ownFunction() { //not accessable //var newInt1 = Constants.testInt + 1 var newInt2 = Constants.testStrLen newInt2 = newInt2 + 1 print("Print ownFunction testStr=\(Constants.testStr)") print("Print ownFunction newInt2=\(newInt2)") } } let newInt = MyClass.Constants.testStrLen print("Print testStr=\(MyClass.Constants.testStr)") print("Print testInt=\(newInt)") let myClass = MyClass() myClass.ownFunction() MyClass.Constants.singletonFunction()

Як це пов’язано з питанням?
Франклін Ю
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.