Is it possible to define enum-like type for string? I know about enums but don't want to use enums in this case, I want to use it as if it's just a string.
type Blog = object
text: string
priority: "low" | "normal" | "high"
echo Blog(text: "something...", priority: "high")
Enums can have a string value attached to it. A converter could be used for automatic parsing of string to enum. Example (playground):
import strutils # for parseEnum
type
Priority = enum
pLow = "low", pNormal = "normal", pHigh = "high"
Blog = object
text: string
priority: Priority
converter toPriority(s: string): Priority = parseEnum[Priority](s)
echo Blog(text: "something...", priority: "high")
#note that parseEnum is style insensitive
echo Blog(text: "something...", priority: "LOW")
try:
echo Blog(text: "something...", priority: "medium")
except:
echo getCurrentExceptionMsg()
output:
(text: "something...", priority: high)
(text: "something...", priority: low)
invalid enum value: medium
type definition and converter could probably be automated in a macro such as:
stringEnum:
Priority = ["low", "medium", high"]
Implementation of macro left as an exercise for the reader :)
Related
Is there any way that we can define types that are checked during typescript compile time only. I want user to define a value to variable (ie not going to change on runtime) and i want to check if that value matches some criteria. For example, user need to set numeric value but cannot set less then 5, or set an string with specific format or validate with regex eg email. or string that must follow specific format or it can be pass through some condition and pass the test or else throw the error with defined message
Is there any way to achieve this in typescript??
Numeric value
You are allowed to create a union of allowed numeric values. But then you have to set maximum allowed value and compute range. See this answer and my article.
Here you have small example:
type MAXIMUM_ALLOWED_BOUNDARY = 999
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? [...Result, Result['length']][number]
: ComputeRange<N, [...Result, Result['length']]>
)
type NumberRange = ComputeRange<MAXIMUM_ALLOWED_BOUNDARY>
type Except<N extends number, CustomRange extends number> = Exclude<CustomRange, N>
type GreaterThanFive = Except<ComputeRange<5>, NumberRange>
const less: GreaterThanFive = 2 //expected error
const greater: GreaterThanFive = 6 // ok
Playground
String with specific format.
You can use template literal strings
type SpecificFormat = `${string}-${string}`
type StringDigit = `${number}`
const str: SpecificFormat = 'hello-world' // ok
const str2: SpecificFormat = 'hello world' // expected error
const strDigit: StringDigit = '42' // ok
const strDigit2: StringDigit = '42a' // expected error
However, if you want to apply more advanced restrictions, for instance check whether it is a valid HEX value or email you need to use duplicate variable value in a type or use extra dummy function. See example:
type ComputeRange<
N extends number,
Result extends Array<unknown> = [],
> =
(Result['length'] extends N
? Result[number]
: ComputeRange<N, [...Result, Result['length']]>
)
type HexNumber = `${ComputeRange<10>}`
type HexString =
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F'
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
type Hex = `${HexNumber}` | HexString;
type StringLength<
Str extends string,
Acc extends string[] = []
> =
(Str extends `${infer S}${infer Rest}`
? StringLength<Rest, [...Acc, S]>
: Acc['length'])
type ValidateLength<
Str extends string,
Length extends number
> =
(StringLength<Str> extends Length
? Str
: never)
type WithHash<T extends string> = `#${T}`
type ValidateHex<
Color extends string,
Cache extends string = '',
> =
Color extends `${infer A}${infer Rest}`
? (A extends ''
? WithHash<Cache>
: (A extends Hex
? ValidateHex<Rest, `${Cache}${A}`>
: never)
) : WithHash<Cache>
const hex: ValidateHex<'ffffff'> = '#ffffff' // ok
const hex2: ValidateHex<'fffffz'> = '#ffffff' // expected error
Playground
If you want to validate function arguments you can check this answer, this answer or my article
If you are interested in email validation you can check this answer or my article
Also it is possible to apply restriction where all chars should be lowercased or uppercased, fir this purpose you can use built in intrinsic utility types:
// credits goes to #jcalz https://stackoverflow.com/questions/68963491/define-a-typescript-type-that-takes-a-lowercase-word#answer-73732194
let str: Lowercase<string>;
str = "abc"; // okay
str = "DEF"; // error in TS4.8+
However, it works only for TS 4.8 +. See my article or this answer
I want to set fields dynamically in groovy so I have a java code that get datas from a database and I set groovy fields using Bindings.setVariable() in java.
I would like to know if it is possible to cast each primitive types in groovy.
String to int, String to float and so on.
So I could always send a string and cast in an other primitive times, it depends of the type of my groovy fields.
#Opal's as solution is good, but I also wanted to mention that the Groovy JDK adds some convenient primitive check and conversion methods to CharSequence, which String implements:
isDouble and asDobule
isFloat and asFloat
isLong and asLong
isInteger and asInteger
Interestingly, it isFloat seems to be greedy, returning true for floating points beyond its range.
['2', '2.2', '2' * 10, "${Double.MAX_VALUE}"].each { s ->
switch (s) {
case { it.isInteger() }:
int i = s.toInteger()
println "String '$s' -> int $i"
break
case { it.isLong() }:
long l = s.toLong()
println "String '$s' -> long $l"
break
case { it.isFloat() }:
float f = s.toFloat()
println "String '$s' -> float $f"
break
case { it.isDouble() }:
double d = s.toDouble()
println "String '$s' -> double $d"
break
default:
println "$s is not a supported primitive"
}
}
prints out
String '2' -> int 2
String '2.2' -> float 2.2
String '2222222222' -> long 2222222222
String '1.7976931348623157E308' -> float Infinity
It depends on what you exactly need, but the following piece of code works well:
assert '2' as Integer == 2
assert '2.2' as Double == 2.2
I would like to store a string as a constant in Swift so I can reuse it and inject variables into it. For example, I can do this in C#:
var template = "Your name is {0} and your age is {1}."
someLabel.text = string.Format(template, "John", 35)
some2Label.text = string.Format(template, "Jane", 33)
How can I accomplish this in Swift so I can reuse the string template?
Use swift's printf-style syntax to save the template and then use it like this:
var template = "Your name is %# and your age is %d."
someLabel.text = String(format: template, "John", 35)
some2Label.text = String(format: template, "Jane", 33)
If you haven't used this style of syntax before here is a rough guide:
%# : String (or, as nhgrif pointed out, the description / descriptionWithLocale property of an NSObject)
%d : Int
%f : Double
%.2f : Double with precision of 2, e.g. 2.2342 -> 2.23
Here's the documentation if you require more precision.
You already have an answer, but if you want type safety and to localize your code, you can use enums like this:
enum Greeting: CustomStringConvertible {
case SayHello(String)
var description:String {
switch (self) {
case .SayHello(let name):
return "Say hello to \(name)?"
}
}
}
let a = Greeting.SayHello("my little friend")
Note that doesn't preclude you from taking a hybrid approach of putting all your string templates in one location and building them in a type safe enum via the String(format:...) approach. You would just need to implement it carefully (but only once).
You can use a template engine such as https://github.com/groue/GRMustache.swift.
A function in swift takes any numeric type in Swift (Int, Double, Float, UInt, etc).
the function converts the number to a string
the function signature is as follows :
func swiftNumbers <T : NumericType> (number : T) -> String {
//body
}
NumericType is a custom protocol that has been added to numeric types in Swift.
inside the body of the function, the number should be converted to a string:
I use the following
var stringFromNumber = "\(number)"
which is not so elegant, PLUS : if the absolute value of the number is strictly inferior to 0.0001 it gives this:
"\(0.000099)" //"9.9e-05"
or if the number is a big number :
"\(999999999999999999.9999)" //"1e+18"
is there a way to work around this string interpolation limitation? (without using Objective-C)
P.S :
NumberFormater doesn't work either
import Foundation
let number : NSNumber = 9_999_999_999_999_997
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 20
formatter.minimumIntegerDigits = 20
formatter.minimumSignificantDigits = 40
formatter.string(from: number) // "9999999999999996.000000000000000000000000"
let stringFromNumber = String(format: "%20.20f", number) // "0.00000000000000000000"
Swift String Interpolation
1) Adding different types to a string
2) Means the string is created from a mix of constants, variables, literals or expressions.
Example:
let length:Float = 3.14
var breadth = 10
var myString = "Area of a rectangle is length*breadth"
myString = "\(myString) i.e. = \(length)*\(breadth)"
Output:
3.14
10
Area of a rectangle is length*breadth
Area of a rectangle is length*breadth i.e. = 3.14*10
Use the Swift String initializer: String(format: <#String#>, arguments: <#[CVarArgType]#>)
For example:
let stringFromNumber = String(format: "%.2f", number)
String and Characters conforms to StringInterpolationProtocol protocol which provide more power to the strings.
StringInterpolationProtocol - "Represents the contents of a string literal with interpolations while it’s being built up."
String interpolation has been around since the earliest days of Swift, but in Swift 5.0 it’s getting a massive overhaul to make it faster and more powerful.
let name = "Ashwinee Dhakde"
print("Hello, I'm \(name)")
Using the new string interpolation system in Swift 5.0 we can extend String.StringInterpolation to add our own custom interpolations, like this:
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Date) {
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: value)
appendLiteral(dateString)
}
}
Usage: print("Today's date is \(Date()).")
We can even provide user-defined names to use String-Interpolation, let's understand with an example.
extension String.StringInterpolation {
mutating func appendInterpolation(JSON JSONData: Data) {
guard
let JSONObject = try? JSONSerialization.jsonObject(with: JSONData, options: []),
let jsonData = try? JSONSerialization.data(withJSONObject: JSONObject, options: .prettyPrinted) else {
appendInterpolation("Invalid JSON data")
return
}
appendInterpolation("\n\(String(decoding: jsonData, as: UTF8.self))")
}
}
print("The JSON is \(JSON: jsonData)")
Whenever we want to provide "JSON" in the string interpolation statement, it will print the .prettyPrinted
Isn't it cool!!
If I have an Alloy model in the following format
one sig player {
name: String,
spot: set position
}
sig position {
Attack: Bool,
accuracy: int,
strength: int,
}
If I want to have a cetain rule such that each player can have 1 to 3 positions. Is there a way to create such a prediction or fact to do this?
Thanks,
You can add an appended fact to the player sig to specify that constraint. The cardinality operator (#) can be used to express the "set size" e.g.,
one sig player {
name: String,
spot: set position
} {
#position <= 1 && position >= 3
}